Answers:
TL; DR: when
关于副作用,and
用于纯布尔表达式。
正如您所注意到的,and
并且when
仅在语法上有所不同,但在其他方面完全等效。
但是,语法上的区别非常重要:除了第一个参数形式外,所有内容都when
包含一个隐式内容progn
。 progn
这是一个固有的命令功能:它只评估最后一个身体形式(除了最后一个身体形式)的副作用,而丢弃它们返回的任何值。
因此,when
它也是命令式形式:它的主要目的是包装副作用形式,因为只有最后形式的值实际上对身体很重要。
and
另一方面,是一个纯函数,其主要目的是查看给定参数形式的返回值:除非您明确包装progn
其任何参数,否则每个参数形式的值都很重要,并且永远不会忽略任何值。
因此,and
和之间的真正区别when
是风格上的:您使用and
纯布尔表达式,并when
保护副作用形式。
因此,这些是不好的样式:
;; `when' used for a pure boolean expression
(let ((use-buffer (when (buffer-live-p buffer)
(file-exists-p (buffer-file-name buffer)))))
...)
;; `and' used as guard around a side-effecting form
(and (buffer-file-name buffer) (write-region nil nil (buffer-file-name buffer)))
这些很好:
(let ((use-buffer (and (buffer-live-p buffer)
(file-exists-p (buffer-file-name buffer)))))
...)
(when (buffer-file-name buffer)
(write-region nil nil (buffer-file-name buffer)))
我知道有些人对此表示不同意见,并乐于使用它and
来防范副作用,但是我认为这确实是不好的风格。我们有这些不同的形式是有原因的:语法很重要。如果没有,我们都只会使用if
,这是Emacs Lisp语义上真正需要的唯一条件形式。所有其他布尔和条件形式都可以用表示if
。
and
是关心返回值。它不一定与使用副作用无关。如果我的程序关心返回值,则使用and
。如果没有,则使用when
。IOW,我when
仅用于副作用,但我很可能progn
在args之一中使用a and
。这是关于是否返回值的问题,不是关于是否单独事项。
and
在我所知的任何Lisp中都不是函数。在Emacs Lisp中,它是一种特殊形式,在Common Lisp中,它是一个宏,仅仅是因为它被期望具有短路行为(不可能通过函数来实现,因为它们始终会评估其参数)。
and
函数是不正确的。事实与问题的相关性无关紧要,我们应该始终使用正确的术语,仅此而已。
nil
,表示“假”,“空列表”,“无效”等所有内容。例如,在Scheme和Racket中,when
是void
(即“无意义”),而and
它是#f
(“假”)。尽管对于Elisp来说这是N / A,但这是Lisp多面手可能考虑的事情。
让我说,开始(and a b)
和(when a b)
你的榜样做同样的事:一是a
评估。b
被评估,如果a
是真的#。
但是 and
和when
用于不同的事物。
你可以使用(and a b)
返回真#如果这两个a
和b
是真正的#(或不为零); 和nil
其他。
您会使用(when a b)
或更准确地说,
(when a
;; do something like b
)
当您希望“ b”代码在且仅当a
为true #时执行。
这是一起使用when
和的示例and
:
(when (and a b)
(do-c))
上面的函数do-c
被调用仅当a
和b
是真正的#。
when
在此处查找部分)and
在此处查找部分)#所有对true的引用均指布尔TRUE。
and
t
如果其所有参数均为非nil,则不返回,但返回最后一个参数的值。
t
表示布尔值TRUE或nonnil。谢谢,我将在回答中阐明这一点。
(when (and a b) c)
)中。另外,有关如何使用and
和when
建议使用的部分实际上是通常使用它们的方式,但是此问题的根本原因是我经常看到它们的用法不同(例如,参见我在问题中链接的答案)。