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

时间:2019-06-19 00:37:44

标签: common-lisp symbols

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

(defun fun (&key (x nil)) x)
(defparameter expr1 (list 'fun :x 2))
(defparameter expr2 (list 'fun (intern "x" "KEYWORD") 2))

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

的错误
  

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

为什么会出现此错误?以及我该如何解决?

2 个答案:

答案 0 :(得分:7)

原因是通常在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,与符号{{1}不同}(这就是错误的原因)。请注意,在REPL中打印带有小写字母的符号时,与:X中一样,它由管道字符(|)包围,因此,再次阅读时,小写字符不变:

|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)) 会按预期工作。

答案 1 :(得分: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?|