有条件的“和”与“何时”


13

这是对该答案的评论的后续。以下代码似乎是等效的:

(and a b)

(when a b)

当然,and让你把更多的条件:(and a b c d)手段(when (and a b c) d)

我倾向于when只用来表示分支。有实际差异吗?使用其中一个更好吗?

我手头没有Emacs的C源代码;and是C函数;when是一个扩展为的宏if,它本身是C函数。


“当然,让我们”应该是“当然,而让我们”,但这只是2个字符的更改,是不允许的编辑。没有覆盖。
哈维2015年

Answers:


18

TL; DR: when关于副作用,and用于纯布尔表达式。

正如您所注意到的,and并且when仅在语法上有所不同,但在其他方面完全等效。

但是,语法上的区别非常重要:除了第一个参数形式外,所有内容都when包含一个隐式内容prognprogn这是一个固有的命令功能:它只评估最后一个身体形式(除了最后一个身体形式)的副作用,而丢弃它们返回的任何值。

因此,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


2
IMO(即我使用的样式)and关心返回值。它不一定与使用副作用无关。如果我的程序关心返回值,则使用and。如果没有,则使用when。IOW,我when 用于副作用,但我很可能progn在args之一中使用a and。这是关于是否返回值的问题,不是关于是否单独事项。
Drew

5
and在我所知的任何Lisp中都不是函数。在Emacs Lisp中,它是一种特殊形式,在Common Lisp中,它是一个宏,仅仅是因为它被期望具有短路行为(不可能通过函数来​​实现,因为它们始终会评估其参数)。
Mark Karpov 2015年

2
@lunaryorn,是的,它并不是真正相关的,但这是事实,因此我认为编写不是and函数是不正确的。事实与问题的相关性无关紧要,我们应该始终使用正确的术语,仅此而已。
Mark Karpov

2
好吧,我不认为“每种论证形式的价值都很重要”与这种解释是一致的。通过说没有一种形式被评估只是为了丢掉它的价值本来可以更好地表达出来。
Harald Hanche-Olsen

3
有点过时,但是:在Lisps中,差异不仅仅在于风格上,它们不是双关语nil,表示“假”,“空列表”,“无效”等所有内容。例如,在Scheme和Racket中,whenvoid(即“无意义”),而and它是#f(“假”)。尽管对于Elisp来说这是N / A,但这是Lisp多面手可能考虑的事情。
格雷格·亨德肖特

4

让我说,开始(and a b)(when a b)你的榜样做同样的事:一是a评估。b被评估,如果a真的

但是 andwhen用于不同的事物。

  • 你可以使用(and a b)返回如果这两个ab真正的(或不为零); 和nil其他。

  • 您会使用(when a b)或更准确地说,

    (when a
       ;; do something like b
       )
    

    当您希望“ b”代码在且仅当atrue #时执行


这是一起使用when和的示例and

(when (and a b)
   (do-c))

上面的函数do-c被调用仅当ab真正的


学习参考

所有对true的引用均指布尔TRUE。


3
andt如果其所有参数均为非nil,则不返回,但返回最后一个参数的值。
有意义的用户名

1
t表示布尔值TRUE或nonnil。谢谢,我将在回答中阐明这一点。
Kaushal Modi

我认为您的答案不会比我在问题中已经说的要远。我知道两者都可以,您给出的最后一个示例已经出现在我的问题((when (and a b) c))中。另外,有关如何使用andwhen建议使用的部分实际上是通常使用它们的方式,但是此问题的根本原因是我经常看到它们的用法不同(例如,参见我在问题中链接的答案)。
克莱门特

从纯函数构造的角度来看,when用于非终止求值,并且用于直接符号和布尔逻辑。函数式编程需要这种区别;命令式编程使这一切变得模糊。
Emacs用户

1
我不认为“布尔真”比“真”更清楚。
YoungFrog
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.