在许多语言中,如果你按照
的方式写一些东西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))
如果评估为真,那么b和c也会被评估,还是会被忽略?
谢谢!
答案 0 :(得分:12)
由于您回答了自己的问题,请注意虽然在您的示例中,b和c可能未在(或abc)调用中进行评估,但在此之前评估let绑定,因此太懒惰到优化此函数无论如何都要评估电话。 Clojure并不像那样懒惰。
要明确:要有条件地评估函数调用,您需要在or
调用中将表达式进行评估,基本上:
(or (simple-function args)
(complex-function args)
(too-lazy-to-optimize-this-function args))
答案 1 :(得分:11)
其他答案都很好,但如果有疑问,你可以随时在REPL上测试它:
user=> (or true (do (println "hello") true))
true
user=> (or false (do (println "hello") true))
hello
true
答案 2 :(得分:4)
如有疑问,请咨询the documentation:
或
宏
用法:(or) (or x) (or x & next)
从左到右逐个评估exprs。如果是表格 返回逻辑真值,或返回该值而不是 评估任何其他表达式,否则返回 最后一个表达式的值。 (或)返回nil。
(强调我的。)
documentation for and
表明它的行为也相同。
答案 3 :(得分:1)
一旦我完成了这个问题的输入,我就意识到我可以查看'或'的文档。
来自文档: “从左到右一次评估exprs。如果是表格 返回逻辑真值,或返回该值而不返回 评估任何其他表达式,否则返回 最后一个表达式的值。 (或)返回nil。“
答案 4 :(得分: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
答案 5 :(得分:0)
if (foo() || bar() || foobar()) { /* do stuff */ }
到
(if (or (foo) (bar) (boobar)) (comment do stuff))
或
(when (or (foo) (bar) (boobar)) (comment do stuff))