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。
andt如果其所有参数均为非nil,则不返回,但返回最后一个参数的值。
t表示布尔值TRUE或nonnil。谢谢,我将在回答中阐明这一点。
(when (and a b) c))中。另外,有关如何使用and和when建议使用的部分实际上是通常使用它们的方式,但是此问题的根本原因是我经常看到它们的用法不同(例如,参见我在问题中链接的答案)。