我在理解with
关键字的工作方式时遇到了问题。特别是,我认为它与let
语句相同,但是没有遵循。
例如,这两个代码“应该”打印相同的值,但是第一个给出(nil nil)
,而后者可以正常工作。
(loop for c in clauses
with p = (car c)
collect p)
(loop for c in clauses
collect (car c))
答案 0 :(得分:7)
with
用于创建局部辅助变量。它们在循环开始前初始化,因此与编写此代码相同:
(let ((p (car c))
(loop for c in clauses
collect p))
除了c
的同时nil
以(car c)
的形式存在的事实。我认为是因为loop
一开始就一次性创建了所有变量,就像我在此处创建p
一样。
您正在寻找for
:
(loop
for c in clauses
for p = (car c)
collect p)
为什么不进行销毁呢?:
(loop
for (p) in clauses
collect p)
答案 1 :(得分:5)
有助于更好地理解LOOP
的一件事是LOOP
具有三个不同的子句部分
(loop
; first a single optional NAME clause
; then zero or more variable clauses with WITH, INITIAL, FINALLY and/or FOR
; then zero or more main clauses with DO, RETURN, COLLECT, APPEND, SUM, NCONC, ...
)
必须保持这些子句部分的顺序。
有两种引入变量的方法:FOR
和WITH
。 FOR
会在每次迭代中更新变量,而WITH
只会执行一次。您可以在正确的部分中以任何顺序编写这些子句,但是通常WITH
绑定及其值将在FOR
变量具有正确值之前创建-尽管并非总是如此。
LispWorks警告您的特定代码:
CL-USER 6 > (loop for c in '((1) (2) (3))
with p = (car c)
collect p)
Warning: Local Variable Initialization clause
(the binding of P) follows iteration forms but will be evaluated before them.
(NIL NIL NIL)
经常
(loop for c in clauses
with p = (car c)
collect p)
将通过以下方式实现:
(...
(let ((c nil) ...)
(let ((p (car c))) ; your (CAR ...) form
; iteration code ...
)))
在这种情况下,您有一些“运气”,因为(car nil)
可以正常工作,只有结果不是您所期望的-默默无闻。
但这会产生错误:
(loop for c in '((1) (2) (3))
with p = (1+ c) ; note the 1+ instead of CAR
collect p)
此处(1+ nil)
不起作用,并且会出错,因为函数1+
仅接受数字作为参数。您不会看到意外的结果,但是会看到错误。
样式规则
FOR
和WITH
子句。WITH
子句之前写入FOR
子句。