В чем разница между переменной и символом в LISP?

По размаху? Фактическая реализация в памяти? Синтаксис? Например, если (пусть а 1) Является ли «а» переменной или символом?


person Gaurav Dadhania    schedule 28.08.2010    source источник
comment
clisp — это конкретная реализация Common Lisp, и ваш вопрос касается языка, поэтому я позволил себе изменение ваших тегов.   -  person Gilles 'SO- stop being evil'    schedule 28.08.2010


Ответы (7)


Ответ Йорга указывает в правильном направлении. Позвольте мне добавить немного к нему.

Я расскажу о Лиспах, похожих на Common Lisp.

Символы как структура данных

Символ — это реальная структура данных в Лиспе. Вы можете создавать символы, вы можете использовать символы, вы можете хранить символы, вы можете передавать символы, и символы могут быть частью более крупных структур данных, например списков символов. Символ имеет имя, может иметь значение и может иметь функциональное значение.

Таким образом, вы можете взять символ и установить его значение.

(setf (symbol-value 'foo) 42)

Обычно пишут (setq foo 42), или (set 'foo 42), или (setf foo 42).

Символы в коде, обозначающие переменные

Но!

(defun foo (a)
  (setq a 42))

or

(let ((a 10))
   (setq a 42))

В обеих формах выше в исходном коде есть символы, и a записывается как символ, и использование функции READ для чтения этого источника возвращает символ a в некотором списке. Но операция setq НЕ устанавливает значение символа a в 42. Здесь LET и DEFUN обозначают ПЕРЕМЕННУЮ a, которую мы записываем с помощью символа. Таким образом, операция SETQ затем устанавливает значение переменной в 42.

Лексическая привязка

Итак, если мы посмотрим на:

(defvar foo nil)

(defun bar (baz)
  (setq foo 3)
  (setq baz 3))

Мы вводим глобальную переменную FOO.

В баре первый SETQ задает значение символа глобальной переменной FOO. Второй SETQ устанавливает для локальной переменной BAZ значение 3. В обоих случаях мы используем один и тот же SETQ и записываем переменную как символ, но в первом случае FOO предоставляет глобальную переменную, и эти значения хранятся в значении символа. Во втором случае BAZ обозначает локальную переменную и как сохраняется значение, мы не знаем. Все, что мы можем сделать, это получить доступ к переменной, чтобы получить ее значение. В Common Lisp нет способа взять символ BAZ и получить значение локальной переменной. У нас нет доступа к привязкам локальных переменных и их значениям с использованием символов. Это часть того, как лексическое связывание локальных переменных работает в Common Lisp.

Это приводит, например, к наблюдению, что в скомпилированном коде без записанной отладочной информации символ BAZ исчез. Это может быть регистр в вашем процессоре или реализованный как-то иначе. Символ FOO все еще там, потому что мы используем его как глобальную переменную.

Различные варианты использования символов

Символ — это тип данных, структура данных в Лиспе.

Переменная — это концептуальная вещь. Глобальные переменные основаны на символах. Локальных лексических переменных нет.

В исходном коде мы пишем всевозможные имена для функций, классов и переменных, используя символы.

Есть некоторое концептуальное совпадение:

(defun foo (bar) (setq bar 'baz))

В приведенном выше ИСХОДНОМ коде defun, foo, bar, setq и baz являются символами.

DEFUN — это символ, предоставляющий макрос. FOO — это символ, обеспечивающий функцию. SETQ — это символ, предоставляющий специальный оператор. BAZ — это символ, используемый в качестве данных. Таким образом, цитата перед BAZ. BAR — это переменная. В скомпилированном коде его символ больше не нужен.

person Rainer Joswig    schedule 28.08.2010

Цитата из Common Lisp HyperSpec:

символ n. объект типа типа символ.

переменная n. a привязка в «переменной» пространстве имен .

binding n. связь между именем< /a> и то, что обозначает имя. (…)

Время объяснения.

То, что Лисп называет символами, довольно близко к тому, что многие языки называют переменными. В первом приближении символы имеют значения; когда вы оцениваете выражение x, значением выражения является значение символа x; когда вы пишете (setq x 3), вы присваиваете новое значение x. В терминологии Лиспа (setq x 3) связывает значение 3 с символом x.

Особенностью Лиспа, которой нет в большинстве языков, является то, что символы являются обычными объектами (символы являются объектами первого класса в терминологии языков программирования). Когда вы пишете (setq x y), значение x становится таким же, каким было значение y во время присваивания. Но вы можете написать (setq x 'y), и в этом случае значение x будет символом y.

Концептуально говоря, существует среда, представляющая собой ассоциативную таблицу из символы к значениям. Оценка символа означает поиск его в текущей среде. (Среды также являются первоклассными объектами, но это выходит за рамки этого ответа.) binding относится к конкретной записи в среде. Однако есть дополнительная сложность.

Большинство диалектов Лиспа имеют несколько пространств имен, по крайней мере, пространство имен переменных и пространство имен функций. На самом деле среда может содержать несколько записей для одного символа, по одной записи для каждого пространства имен. Строго говоря, переменная — это запись в среде в пространстве имен переменных. В повседневной терминологии Лиспа символ часто упоминается как переменная, если вас интересует его связывание с переменной.

Например, в (setq a 1) или (let ((a 1)) ...) a является символом. Но поскольку конструкции воздействуют на привязку переменной для символа a, в этом контексте принято ссылаться на a как на переменную.

С другой стороны, в (defun a (...) ...) или (flet ((a (x) ...)) ...) a также является символом, но эти конструкции действуют на привязку его функции, поэтому a не будет считаться переменной.

В большинстве случаев, когда символ появляется в выражении без кавычек, он оценивается путем поиска привязки его переменной. Основное исключение состоит в том, что при вызове функции (foo arg1 arg2 ...) используется привязка функции для foo. Значение символа в кавычках 'x или (quote x) равно самому себе, как и в любом выражении в кавычках. Конечно, существует множество специальных форм, в которых не нужно заключать символ в кавычки, в том числе setq, let, flet, defun и т. д.

person Gilles 'SO- stop being evil'    schedule 28.08.2010

символ – это название объекта. переменная — это изменяемый указатель на изменяемое место хранения.

В показанном фрагменте кода let и a являются символами. В рамках блока let символ a обозначает переменную, которая в данный момент привязана к значению 1.

Но имя вещи не есть сама вещь. Символ a не является переменной. Это имя переменной. Но только в этом конкретном контексте. В другом контексте имя a может относиться к совершенно другой вещи.

Пример: символ jaguar может, в зависимости от контекста, обозначать

person Jörg W Mittag    schedule 28.08.2010
comment
+1 за упоминание символов, означающих разные вещи в разных контекстах. Это действительно помогает понять разницу между x и #'x и 'x. - person Baggers; 09.01.2013

Lisp использует окружения, похожие на карты (ключ -> значение), но с дополнительными встроенными механизмами для связывания окружений и управления привязками.

Теперь символы в значительной степени представляют собой ключи (кроме символов специальной формы) и указывают на значение,
т.е. функцию, целое, список и т. д.
Поскольку Common Lisp дает вам возможность изменять значения, то есть с помощью setq, символы в некоторых контекстах
(ваш пример) также переменные.

person Nick Dandoulakis    schedule 28.08.2010

Символ — это объект данных Лиспа. «Форма» Лиспа означает объект Лиспа, предназначенный для оценки. Когда сам символ используется как форма Лиспа, т. е. когда вы вычисляете символ, результатом является значение, связанное с этим символом. Способ, которым значения связаны с символами, является глубокой частью языка Лисп. Независимо от того, объявлен ли символ «особым» или нет, сильно меняется способ работы оценки.

Лексические значения обозначаются символами, но вы не можете сами манипулировать этими символами как объектами. На мой взгляд, объяснять что-либо в Лиспе с точки зрения «указателей» или «местоположений» — не лучший способ.

person Dan Weinreb    schedule 30.08.2010

Добавление примечания к приведенным выше ответам:

Новички в Лиспе часто точно не знают, для чего нужны символы, помимо имен переменных. Я думаю, что лучший ответ заключается в том, что они похожи на константы перечисления, за исключением того, что вам не нужно объявлять их перед использованием. Конечно, как объясняли другие, они также являются объектами. (Это не должно показаться странным пользователям Java, в которой константы перечисления также являются объектами.)

person Scott L. Burson    schedule 03.09.2010
comment
Интересный ответ - person SpectreVert; 19.11.2020

Символ и переменная - это две разные вещи. Как в математике символ является значением. И переменные имеют тот же смысл, что и в математических.

Но ваше замешательство произошло из-за того, что символ является метапредставлением переменной.

Это если вы сделаете

(setq a 42)

Вы просто определяете переменную a. Между прочим, обычный лисп хранит его в виде структуры символа.

В простонародье символ губ представляет собой структуру с другим свойством. К каждому можно получить доступ с помощью таких функций, как symbol-name, symbol-function...

В случае переменной вы можете получить доступ к ее значению через ssymbol-value

? (symbol-value 'a)
42

Это не обычный случай получения значения a.

? a
42

Обратите внимание, что символы являются самооценивающимися, что означает, что если вы спросите символ, вы получите символ, а не symbol-value.

? 'a
A
person mathk    schedule 28.08.2010