Хотите получить доступ к лексически определенным функциям, используя EVAL в CLISP
Почему этот кусок кода не работает?
(setf x '(foo bar (baz)))
(labels
((baz () (print "baz here")))
(baz) ;works
(eval (third x))) ;fails with the below message
*** - EVAL: undefined function BAZ
Я использую GNU CLISP.
2 ответа
В Common Lisp, eval
оценивает его аргумент в нулевой лексической среде, поэтому ваша лексически связанная функция baz
не может быть найден
Хотя стандарт Common Lisp не предоставляет переносимого способа доступа к лексической среде и вызова eval с ее помощью, ваша реализация может иметь эту функциональность. Например, в CLISP:
cs-user> (setf x '(foo bar (baz)))
(foo bar (baz))
cs-user> (labels ((baz () (print "baz here")))
(eval-env (third x) (the-environment)))
"baz here"
"baz here"
cs-user>
Смотрите ответ Geocar для других подходов.
Потому что обычный лисп не имеет специальных функций.
Проверьте описание EVAL
:
Оценивает форму в текущей динамической среде и нулевой лексической среде.
Поскольку лексическая среда пуста, ваш baz
функция (определяется labels
) не доступен. Вы могли бы подумать, что это можно исправить, положив baz
в динамичной среде (вы можете захотеть что-то вроде (declare (special baz))
или же (declare (special (function baz)))
или как-то так) но увы: нет способа сделать это.
Вы можете смоделировать это самостоятельно, создав:
(defvar baz* nil)
(defun baz (&rest args) (apply baz* args))
Затем вам нужно установить динамически baz*
Вместо того, чтобы использовать labels
:
(setf x '(foo bar (baz)))
(let ((baz* (lambda () (print "baz here"))))
(eval (third x)))
Причина в том, что в спецификации просочились только некоторые подробности об оптимизации. По сути, каждому вызову функции потребуется некоторая заглушка, если только компилятор не сможет доказать, что функция никогда не будет определена динамически. Это сложно сделать эффективно, и большинство программистов на CL никогда не делали этого, поэтому разработчики спецификаций просто запретили это.
Как видите, как и в большинстве вещей в CL, вы можете легко получить его самостоятельно, если вам это нужно. Тем не мение. Учитывая, что большинство программистов на CL никогда не делают этого, вы можете пересмотреть, почему вы пытаетесь делать что-то таким образом.