Lisp括号问题

Don*_*Lun 8 lisp common-lisp land-of-lisp

这段代码来自书:"Land of Lisp"第一版来自书.当我读它时,我认为有一个括号"("在第二行的"at-loc-p"之前没有必要,")"就在第三行的loc之后.

(defun person-at (loc pers per-locs)
       (labels ((at-loc-p (pers)
                 (eq (cadr (assoc pers per-locs)) loc)))
         (remove-if-not #'at-loc-p pers)))
Run Code Online (Sandbox Code Playgroud)

但是当我测试这个时,

(defun person-at (loc pers per-locs)
       (labels (at-loc-p (pers)
                 (eq (cadr (assoc pers per-locs)) loc))
         (remove-if-not #'at-loc-p pers)))
Run Code Online (Sandbox Code Playgroud)

它出来了:

AT-LOC-P中的必需参数与lambda列表不匹配(CCL :: FUNCNAME CCL :: LAMBDA-LIST&BODY CCL :: LABELS-FUNCTION-BODY).
[CCL类型的条件:: SIMPLE-PROGRAM-ERROR]

我不安静理解.需要帮忙.谢谢.

dan*_*lei 11

LABELS

(defun person-at (loc pers per-locs)
  (labels ((at-loc-p (pers)
             (eq (cadr (assoc pers per-locs)) loc)))
    (remove-if-not #'at-loc-p pers)))
Run Code Online (Sandbox Code Playgroud)

有语法labels ((function-name lambda-list [[local-declaration* | local-documentation]] local-form*)*) declaration* form*,所以你必须提供一个本地函数定义列表才能工作.

由于这些本地函数定义本身是括号,因此您必须传递labels此结构的列表:((fun1 (...) ...) (fun2 (...) ...) ...).

不幸的是,堆栈跟踪和错误消息在这里发现错误并不是很有帮助,因为消息不会告诉您问题所在labels,并且它也不是跟踪中的最顶层.这4: (CCL::NX1-LABELS ...将是一个提示(本地机器上的调试器缓冲区).

看看的文档labelsHyperspec了解更多信息.


ffr*_*end 7

在其他语言中,不是Lisps,括号通常用于对运算符进行分组,因此在许多情况下都是可选的.但在Lisp中,括号总是有意义的.可能没有额外或可选的括号.

大多数情况下,表达式括号表示函数或宏应用:

(foo 1)
Run Code Online (Sandbox Code Playgroud)

在这种情况下,在表达开始时可能出现两个括号,例如,当表达式的第一个元素是另一个表达式时,它被计算为函数本身.例如,想象函数make-adder,它接受一个数字并返回另一个部分应用加法的函数(顺便说一句,它是currying的一个例子):

(defun make-adder (number)
   (lambda (another-number) (+ number another-number)))
Run Code Online (Sandbox Code Playgroud)

我们可以用increment这种方式创建函数变量,然后将它应用于变量:

(defvar increment (make-adder 1))
(increment 5)                      ; ==> 6
Run Code Online (Sandbox Code Playgroud)

但是我们也可以直接调用它(好吧,这在Common Lisp中不起作用,但是在其他Lisps中使用相同的语法,称为"Lisp-1",所以我相信这里值得一提):

((make-adder 1) 5)                 ; ==> 6
Run Code Online (Sandbox Code Playgroud)

在开头做双括号.当然,两个括号都是强制性的.

最后一个案例描述了你的情况,就是当语言或用户宏使用列表列表时(你还记得,Lisp程序本身就是表达式列表的列表吗?).例如,defun知道它的第一个参数必须是一个符号,它的第二个参数必须是一个列表.并且labels宏知道,它的第一个参数必须是一个定义列表,每个定义都是一个列表.它允许用户一次定义多个标签:

(labels ((definition-1) (definition-2) ...) 
   (do-this) (do-that) ...)
Run Code Online (Sandbox Code Playgroud)

所以,你可以看到,每个括号都意味着什么,你不能自己放弃它们.

  • 99.9%的情况下你是正确的,但我认为有几个模糊的情况,其中括号在CL中实际上是可选的.例如,`(defstruct sf)`和`(defstruct s(f))`. (3认同)
  • @Ken:好吧,围绕`f`的parens似乎是可选的,但实际上它们定义了一个行为略有不同的宏:`(defstruct sf)`定义了槽名和`(defstruct s(f))`定义插槽名称,可能是initform和插槽选项.并且在每种情况下都严格定义了数量的parens. (2认同)