Причина в том, что обычно в Common Lisp каждый символ при чтении преобразуется в заглавные буквы (это стандартное поведение и может быть изменено), так что:
(defun fun (&key (x nil)) x)
(defparameter expr1 (list 'fun :x 2))
фактически читается как:
(DEFUN FUN (&KEY (X NIL)) X)
(DEFPARAMETER EXPR1 (LIST 'FUN :X 2))
, в то время как intern
получает строку в качестве первого параметра и не преобразует ее, так что в вашем примере "x" интернирован как символ :x
, который отличается от символа :X
(и это является причиной ошибки).Обратите внимание, что когда символ с строчными буквами печатается в REPL, он окружается символами канала (|
), как в |x|
, поэтому при повторном чтении строчные символы не изменяются:
CL-USER> :x
:X
CL-USER> :|x|
:|x|
CL-USER> (format t "~a" :|x|)
x
NIL
Чтобы решить вашу проблему, вы можете просто написать строку непосредственно в верхнем регистре:
(defparameter expr2 (list 'fun (intern "X" "KEYWORD") 2))
, а затем (eval expr2)
работает как задумано.