Являются ли переменные и символы разными в Лиспе? - PullRequest
4 голосов
/ 12 сентября 2011

numberp является предикатом в Лиспе, а (numberp 1) возвращает T, как и ожидалось. Но если я наберу в консоли только numberp, появится сообщение о том, что имя переменной не определено.

Какая разница между этими 2?

Ответы [ 3 ]

12 голосов
/ 12 сентября 2011

Вопрос уже немного неправильный.

Мы говорим о разных вещах в Common Lisp:

  • symbol : это структура данных в Lisp.Символ - это объект данных с именем, значением, функцией, пакетом и, возможно, другим.

В Common Lisp символ может иметь как значение, так и функцию (или макрос).

  • a переменная является идентификатором значения в коде Лиспа

Существуют переменные верхнего уровня, определенные с помощью DEFVAR и DEFPARAMETER.Существуют также локальные переменные, определенные с помощью LAMBDA, DEFUN, LET, LET * и др.

(defun foo (i-am-a-variable) ...)

(defparameter *i-am-a-global-variable* ...)
  • поименованная функция является идентификатором функции в коде Lisp.Именованные функции представлены на верхнем уровне DEFUN, DEFGENERIC и DEFMETHOD.Существуют также локальные именованные функции, определенные FLET и LABELS.

Пример:

(defun i-am-a-function (foo) ...)

(flet ((i-am-a-function (foo) ...)) ...)

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

Пример:

(type-of (second '(defun foo () nil)))  -->  SYMBOL

Давайте посмотрим на функции и переменные:

(defun foo ()
  (let ((some-name 100))
    (flet ((some-name (bar) (+ bar 200)))
       (+ some-name (some-name some-name)))))

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

(+ some-name (some-name some-name))

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

Это имеетпрактический эффект, что вы можете сделать что-то вроде этого:

(defun parent (person) ...)

(defun do-something (parent)
   (parent parent))

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

В Scheme есть только одно пространство имен, и мы должны написать

(define (foo lst) (list 'a lst 'n))

, где в Common Lisp мы можем написать:

(defun foo (list) (list 'a list 'n))

В Common Lisp нет необходимости писать lst вместо list - потому что нет конфликта между локальной переменной list и глобальной функцией list.

Доступ кдругое пространство имен

Чтобы получить объект функции, хранящийся в переменной, вы можете использовать FUNCTION.

(let ((my-function (function numberp)))
  (funcall my-function 10))

(function foo) можно записать короче как #'foo.

FUNCALL вызывает объект функции.

OTOH, если вы хотите сохранить объект функции из переменной в пространстве имен функции, есть только один способ:

(setf (symbol-function 'foo) my-function)

Также необходимо, чтобы объект был действительно функцией, а не чем-то другим (число, строка, ...).В противном случае вы увидите ошибку.

Побочным эффектом этого является то, что Common Lisp никогда не должен проверять, действительно ли в (foo bar) FOO является функцией.Нет никакой возможности, что он может быть отличным от функции или неопределенным.

8 голосов
/ 12 сентября 2011

Функции и переменные живут в разных пространствах имен в Common Lisp.

Таким образом, когда вы используете имя в позиции, где ожидается функция (то есть в начале оцениваемого списка), оно ищет функцию (или макрос) с этим именем. Если вы используете то же имя в позиции, где ожидается переменная, она ищет переменную с этим именем.

В вашем случае есть функция с именем numberp, но не переменная с именем numberp, поэтому второй случай вызывает ошибку.

0 голосов
/ 13 декабря 2011

Одно из различий между Scheme (так сказать, одним диалектом Lisp) и Common Lisp заключается в том, что в Scheme существует одно пространство имен для переменных и функций, тогда как в CL есть два отдельных пространства имен. Таким образом, в Scheme «define» устанавливает эту единственную ассоциацию «имя-значение», тогда как в CL есть «define» для значения и «defun» для ассоциации функции.

Итак, в CL вы можете:

(define foo ...something...)
(defun foo ...somethingElse...)

чтобы запутать читателя.

В схеме есть только один:

(define foo something)

Если это хорошо или плохо, то это был почти религиозный спор в прошлом ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...