用两个管道包围的关键字符号

ore*_*uro 4 symbols common-lisp

假设fun下面的代码中有一个函数,我的目标是expr2在下面进行评估。

(defun fun (&key (x nil)) x)
(defparameter expr1 (list 'fun :x 2))
(defparameter expr2 (list 'fun (intern "x" "KEYWORD") 2))
Run Code Online (Sandbox Code Playgroud)

如预期的那样,(eval expr1)给出了2,但是(eval expr2)给出了类似的错误

***-FUN:非法的关键字/值对:| x |,参数列表中的2。允许的关键字是(:X)下列重新启动可用:ABORT:R1中止主循环

为什么会发生此错误?以及如何解决?

Ren*_*nzo 7

原因是通常在Common Lisp中,每个符号在读取时都会转换为大写字母(这是标准行为,可以更改),因此:

(defun fun (&key (x nil)) x)
(defparameter expr1 (list 'fun :x 2))
Run Code Online (Sandbox Code Playgroud)

实际上是这样的:

(DEFUN FUN (&KEY (X NIL)) X)
(DEFPARAMETER EXPR1 (LIST 'FUN :X 2))
Run Code Online (Sandbox Code Playgroud)

while intern获得一个字符串作为第一个参数,并且不对其进行转换,因此在您的示例中,“ x”被插入为symbol :x,这与symbol不同:X(这就是错误的原因)。请注意,当在REPL中打印带有小写字母的符号时,它与(|)中的一样由管道字符()包围|x|,因此,再次阅读时,小写字符不变:

CL-USER> :x
:X
CL-USER> :|x|
:|x|
CL-USER> (format t "~a" :|x|)
x
NIL
Run Code Online (Sandbox Code Playgroud)

为了解决您的问题,您只需将字符串直接大写即可:

(defparameter expr2 (list 'fun (intern "X" "KEYWORD") 2))
Run Code Online (Sandbox Code Playgroud)

然后(eval expr2)按预期工作。


Rai*_*wig 5

请注意,\|是符号中的转义字符:

? 'foo\xBAR
FOO\xBAR

? '|This is a symbol|
|This is a symbol|

? ':|This is a keyword symbol with spaces and Capital letters!!!|
:|This is a keyword symbol with spaces and Capital letters!!!|

? 'what|? wow |this| also works|?
|WHAT? wow THIS also works?|
Run Code Online (Sandbox Code Playgroud)