if和or在这种情况下有何不同?


#1

就是if的THEN参数为t的情况:


(if (foo)
    t
  (bar))

改写成or形式:

(or (foo)
    (bar))

这两种写法哪种更好?


#2

沒有,


#3

我才明白过来……第二种写法不就是short-cut么……


#4

(foo) 返回 Non-nil 时,两者的返回值不同。

(if 1 t 2)
;; => t

(or 1 2)
;; => 1

下面两者等价(假设 tmp 不会影响 bar

(or (foo)
    (bar))

(let ((tmp (foo)))
  (if tmp
      tmp
    (bar)))

#5

如果不考虑foo为non-nil时的返回值,那么可否认为这两个是等价的?


#6

如果 foonil,两者都返回 bar,且都依次执行过 foo / bar,所以可以认为它们效果相同。


#7

谢谢回答。

所以我不需考虑foo为non-nil时的返回值(此函数的non-nil具体值无意义,或者foo必定返回t/nil),那么如果foo为non-nil时,两者都不会返回bar,同时都只有foo被执行。所以此条件下也可以认为两者效果相同。

我可以如此理解吗?

以及ELisp里有没有类似pass的东西?


#8

可以这么理解,如果只关心 foo 是不是 nil 的话,它们是等价的。比如:

(when (if (foo)
          t
        (bar))
  (do-something))

(when (or (foo)
          (bar))
  (do-something))

#9

我认为从语义的角度来看两者并不同:

(or (foo) (bar)) 和 (or (bar) (foo)) 本质上等价,而短路求值只是一个实现层面的东西。

理论上我们写代码应该完全按照语义,而不是实现层面的东西,所以这两种写法哪种更好取决于语义。


#10

nil本身就可以pass啊

还有个函数ignore,接受任意参数,忽略他们并返回nil


#11

因为lisp所有东西都是表达式,换js py之类的不用短路运算就得三目了


#12

所以我工作的时候就基本不会用短路……毕竟有别人要看。

但是自己写的代码就到处都是…


#13

说白了还是想少打点字……

但是要返回值的话只能三元运算符了……


#14

然而语义就是短路求值。

Eval args until one of them yields non-nil, then return that value.
The remaining args are not evalled at all.
If all args return nil, return nil.

短路求值几乎所有语言都有,大家都懂,又不是什么很难理解的东西。

今天写代码就用到了这个,读取文件做一些计算(如果出错就返回 0):

(or (ignore-errors ...) 0)

if 就很麻烦了。


#15

其实“A and/or B"和“B and/or A"在大多数语言中都不是语义等价的。

但是它们逻辑上等价。


#16

我觉得楼主的例子举错了,应该是这样

(if (foo)
  (foo)
 (bar))

这样就完全等价了。当然更好的写法是用let。不过这种写法都不如or了。 那本 《Writing GNU Emacs Extensions》里推荐这样写。


#17

你这样的 (foo) 就求值了两次,当 (foo) 有副作用时行为就不等价了。

至少也得是 (let ((res (foo))) (if res res (bar)))


#18

只是举例而已,都说了应该用let。你这样写当然是最好啦


#19

这样写打字多 有没有更好的写法 :thinking:


#20

我选择用 Haskell。

讲道理 Haskell 的 hlint 是提倡用 || (binary operator OR) 较于 if_else_then_ 的。

完全是个人主观的问題我沒法给答案。