#common-lisp
Вопрос:
Это example.lisp
:
(defun f (x)
(* x 2))
(defconstant n (f 1))
Когда я пытаюсь скомпилировать файл с помощью (compile-file "example.lisp")
, я получаю сообщение об ошибке при компиляции константы: The function COMMON-LISP-USER::F is undefined
. Как это может быть? Я уже определил функцию f
, прежде чем использовать ее для определения константы. Как мне определить константу, значение которой является возвращаемым значением функции?
Я использую SBCL 2.0.1.
Ответ №1:
От DEFCONSTANT
:
[…] пользователи должны убедиться, что начальное значение может быть вычислено во время компиляции (независимо от того, появляются ли ссылки на name в файле) и что оно всегда принимает одно и то же значение.
Но COMPILE-FILE
и 3.2.3 для компиляции файла требуется только DEFUN
форма для установления того, что F
существует, а не то, что может быть оценено во время компиляции.
Вам нужен LOAD
результирующий файл, чтобы определение было доступно в вашей среде (например, Slime компилирует файл и загружает результат). Аналогично, когда вы оцениваете формы по одной за раз в REPL, определение становится доступным сразу, как если бы был выполнен небольшой цикл компиляции-загрузки.
У вас есть два основных варианта:
- оберните
defun
вeval-when
форму(eval-when (:compile-toplevel :load-toplevel :execute) (defun f (x) (* x 2)))
- поместите две формы в разные файлы, и пусть вторая зависит в системе (в смысле defsystem) от первой:
(defsystem "foo" :components ((:file "define-f") (:file "define-constant")) :serial t)
Комментарии:
1. Я заметил, что могу избежать проблемы, используя
defvar
вместоdefconstant
. Это правильное решение?2. Да, обычно defconstant вычисляет начальное значение во время компиляции, чтобы значение можно было ввести непосредственно позже в том месте, где на него ссылаются; это не относится к defvar, код ссылается только на переменную (которую вы также можете динамически привязывать). Вот почему начальное значение может быть оценено позже (во время загрузки / оценки). Таким образом, оба подхода не эквивалентны в рабочем состоянии, но это, возможно, не важно в вашем случае