5

在许多语言中,如果你写一些类似的东西

if (foo() || bar() || foobar()) { /* do stuff */ }

并且 foo() 返回 true,则不会评估 bar() 和 foobar()。

假设我有以下 Clojure 代码:

(let [a (simple-function args)
      b (complex-function args)
      c (too-lazy-to-optimize-this-function args)]
  (or a b c))

如果 a 计算结果为真,那么 b 和 c 也会被计算,还是会被忽略?

谢谢!

4

6 回答 6

13

由于您回答了自己的问题,请注意,尽管在您的示例中 b 和 c 可能未在 (或 abc) 调用中评估,但在此之前评估了 let 绑定,因此评估了 too-lazy-to-optimize-this-function 调用反正。Clojure 没有那么懒惰。

要清楚:要有条件地评估函数调用,您需要将评估它们的表达式放在or调用中,基本上:

(or (simple-function args)
    (complex-function args)
    (too-lazy-to-optimize-this-function args))
于 2011-11-18T23:50:47.753 回答
11

其他答案都很好,但是如果有疑问,您可以随时在 REPL 上进行测试:

user=> (or true (do (println "hello") true))
true
user=> (or false (do (println "hello") true))
hello
true
于 2011-11-19T02:05:53.330 回答
4

如有疑问,请查阅文档



用法:

   (or)  
   (or x)  
   (or x & next)  

从左到右,一次评估一个 expr。如果一个表单返回一个逻辑真值,或者返回该值并且不计算任何其他表达式,否则它返回最后一个表达式的值。(或)返回零。

(强调我的。)

文档and也显示了它的行为方式。

于 2011-11-18T23:32:19.690 回答
1

当我完成这个问题的输入后,我意识到我可以查看文档中的“或”。

来自文档:“从左到右一次计算一个表达式。如果表单返回逻辑真值,或者返回该值并且不计算任何其他表达式,否则返回最后一个表达式的值.(或)返回零。”

于 2011-11-18T23:30:48.340 回答
1

是的,Clojure 确实有短路评估。

Clojure / 其他 Lisps 中的一个有趣特性是,还可以使用还提供短路评估的新结构来扩展语言。这不能使用大多数其他语言中的函数来完成,因为必须在调用函数之前评估函数的所有参数。

下面是一个在 Clojure 中实现短路 NAND 函数的宏示例:

(defmacro nand 
  ([x] 
    `(not ~x))              ; NAND is equivalent to NOT for one argument
  ([x & xs] 
    `(let [nand# (not ~x)]
       (if nand# 
         true               ; short circuit if we can prove the nand is true
         (nand ~@xs)))))    ; continue with the other expressions otherwise

(nand true true)
=> false

(nand false (println "Expression with a side effect!"))
=> true
于 2011-11-21T02:44:36.337 回答
0
if (foo() || bar() || foobar()) { /* do stuff */ }

(if (or (foo) (bar) (boobar)) (comment do stuff))

或者

(when (or (foo) (bar) (boobar)) (comment do stuff))
于 2011-11-18T23:50:38.370 回答