Как сохранить функцию в переменной в Лиспе и использовать ее

Я хочу сохранить функцию как print в переменной, так что я могу просто напечатать что-то короткое, как pНапример:
В Scheme:

(define print display)
(print "Hello world\n")
;; alternate way
(define print 'display)
((eval print) "Hello world\n")

Тот же подход, похоже, не работает в Common Lisp:

(defvar p 'print)
;;(print (type-of p))
(p "Hello world") ;; Attempt 1
((eval p) "Hello world") ;; >> Attempt 2
((eval (environment) p) "Hello world") ;; Attempt 3

Я получаю эту ошибку с Attempt 1 выше:

*** - EVAL: undefined function P

И это с Attempt 2 а также 3 в Clisp:

*** - EVAL: (EVAL (ENVIRONMENT) P) is not a function name; try using a 
            symbol instead
*** - EVAL: (EVAL P) is not a function name; try using a symbol instead

И с gcl:

Error: (EVAL P) is invalid as a function.
Error: (EVAL (ENVIRONMENT) P) is invalid as a function.

Так:

  • Что значит try using a symbol имею в виду? p определенно symbol; ложно положительный?
  • Что случилось с eval? Разве оценка p сдать процедуру print?
  • я думал Lisp процедуры были first class objects, Почему Attempt 1 не работает, как в Scheme?

РЕДАКТИРОВАТЬ
(Перенесено из комментария ниже)

Мне было интересно почему (setf (symbol-function 'p) #'print) не будет работать таким образом
(setf (symbol-function 'p) 'print), Я получаю следующую (не очень полезную) ошибку:

*** - SYSTEM::%PUTD: PRINT is not a function ;; CLisp
Error: PRINT is not of type LIST. ;; Gcl

Я знаю, что острый знак (#) должен различать функцию и переменную
с тем же именем, но в этом случае есть только один print, функция.

Кроме того, почему это не будет работать с defvar вместо setf вот так:

(defvar (symbol-function 'p) #'print)

еще defvar а также setf оба присваивают значения переменной.
Связанная ошибка:

*** - DEFVAR: non-symbol (SYMBOL-FUNCTION 'P) cannot be a variable ;; Clisp
Error: (SYMBOL-FUNCTION (QUOTE P)) is not of type SYMBOL. ;; Gcl

3 ответа

Решение

Common Lisp - это "Лисп-2". Помимо прочего, первая позиция в вызове функции оценивается в "пространстве имен функции". В вашем случае символ p называет переменную, а не функцию.

Это работает лучше:

(defvar p 'print)

(funcall p "Hello world")

Или, возможно, но вы, вероятно, не хотите делать это:

(setf (symbol-function 'p) #'print)

(p "Hello world")

Common Lisp имеет отдельное пространство имен для функций, что делает подобные операции более многословными, чем со Scheme. Если вы хотели бы похож на верхний уровень (define p display) в CL вы должны сделать макрос:

(defmacro defun-alias (name original-name)
   `(setf (symbol-function ',name) #',original-name))

Который работает так:

(defun-alias pc princ)
(pc "Hello") ; prints hello

В отличие от схемы define это только перезапишет глобальную привязку. Таким образом:

(flet ((test (x) (+ x x))) 
   (defun-alias test +)
   (test 10))

установит глобальное определение #'test в #'+ и вернуть 20. например. это работает как defun,

Чтобы дополнить другие хорошие ответы прямыми ответами на ваши вопросы:

Что означает попытка использования символа? р определенно символ; ложно положительный?

Прочитайте сообщения об ошибках буквально: (EVAL (ENVIRONMENT) P) а также (EVAL P) (без оценки) не символы, а списки. В Common Lisp автомобиль формы не оценивается.

Что случилось с Eval? Разве оценка p не приводит к печати процедуры?

eval никогда не вызывается вашим кодом (см. предыдущий ответ). Даже если бы это было, результатом было бы symbol-value символа print, не symbol-function/fdefinition,

Я думал, что процедуры Лисп были первоклассными объектами. Почему Попытка 1 не работает как в Схеме?

Это не имеет ничего общего с функциями (я думаю, что стандарт Common Lisp не использует термин "процедуры", как это делают стандарты Scheme). Это объекты первого класса. Это работает в Common Lisp:

(let ((p #'print))
  (funcall p "hello world"))

Редактировать:

Ответы на дополнительные вопросы:

Мне было интересно почему (setf (symbol-function 'p) #'print) не будет работать таким образом (setf (symbol-function 'p) 'print),

Это не совсем так, что "резкий знак (#) должен различать функцию и переменную с тем же именем", как вы напишете позже. 'print расширяется до (quote print)так что он оценивает символ print вместо его значения в качестве переменной. #'print расширяется до (function print), поэтому он оценивает значение функциональной ячейки символа print вместо. Будь то print в настоящее время имеет значение как переменная, совершенно не имеет отношения к тому, что #'print оценивает до.

настройка (symbol-function 'p) к символу print очевидно не сделает p вызвать функцию print потому что символ print не совпадает с функцией, связанной с символом print,

Кроме того, почему он не будет работать с defvar вместо setf следующим образом:

(defvar (symbol-function 'p) #'print)

но defvar и setf оба присваивают значения переменной.

setf присваивает значения местам. Семестр (symbol-function 'p) обозначает место, которое является функциональной ячейкой символа p,

defvar определяет новые глобальные переменные. Его первый аргумент должен быть символом, который называет переменную и не может быть каким-либо местом.

Другие вопросы по тегам