В чем разница между переменной и символом в LISP? - PullRequest
22 голосов
/ 28 августа 2010

По объему? Актуальная реализация в памяти? Синтаксис? Например, если (пусть a 1) Является ли 'a' переменной или символом?

Ответы [ 7 ]

20 голосов
/ 28 августа 2010

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

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

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

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

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

(setf (symbol-value 'foo) 42)

Обычно можно написать (setq foo 42)или (set 'foo 42) или (setf foo 42).

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

Но!

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

или

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

В обеих вышеприведенных формах в исходном коде есть символы, и a записывается как символ, и использование функции READ для чтения этого источника возвращает символ a в некотором списке.Но операция setq НЕ устанавливает значение символа a в 42.Здесь LET и DEFUN представляют VARIABLE 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))

В приведенном выше коде SOURCE defun, foo, bar, setq и baz являются символами.

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

12 голосов
/ 28 августа 2010

Цитирование из Common Lisp HyperSpec :

символ номер и объект из тип символ .

переменная n. a переплет в пространстве имен переменных .

связывание n. связь между именем и тем, которое имя обозначает. (…)

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

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

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

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

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

Например, в (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 и т. Д.

10 голосов
/ 28 августа 2010

A символ - это название вещи. переменная является изменяемым указателем на изменяемое место хранения.

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

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

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

4 голосов
/ 28 августа 2010

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

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

3 голосов
/ 30 августа 2010

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

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

1 голос
/ 03 сентября 2010

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

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

1 голос
/ 28 августа 2010

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

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

То есть, если вы делаете

(setq a 42)

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

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

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

? (symbol-value 'a)
42

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

? a
42

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

? 'a
A
...