Optimization Clojure是否具有短路逻辑?
在许多语言中,如果你按照Optimization Clojure是否具有短路逻辑?,optimization,clojure,short-circuiting,Optimization,Clojure,Short Circuiting,在许多语言中,如果你按照 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的计
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的计算结果为true,那么b和c也会被计算,还是会被忽略
谢谢 当我输入完这个问题后,我意识到我可以查看“或”的文档 从文档中: 从左到右一次计算一个表达式。如果 返回逻辑真值,或返回该值而不返回 对任何其他表达式求值,否则返回 最后一个表达式的值。(或)返回nil。“如有疑问,请咨询: 或
宏
用法: 从左到右一次计算一个表达式。如果是表格 返回一个逻辑真值,或返回该值,但不返回 对任何其他表达式求值,否则返回 最后一个表达式的值。(或)返回零 (我的重点。) 显示它的行为方式也相同
if (foo() || bar() || foobar()) { /* do stuff */ }
到
或
由于您回答了自己的问题,请注意,尽管在示例b和c中,可能没有在(或b c)调用中计算let绑定,但在此之前会对let绑定进行计算,因此不会对太懒的函数调用进行优化。Clojure没有那么懒 需要明确的是:要有条件地计算函数调用,需要将计算它们的表达式放在
或调用中,基本上:
(or (simple-function args)
(complex-function args)
(too-lazy-to-optimize-this-function args))
其他答案都很好,但如果有疑问,您可以在REPL上进行测试:
user=> (or true (do (println "hello") true))
true
user=> (or false (do (println "hello") true))
hello
true
是的,Clojure确实有短路评估
Clojure/other 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
我之所以接受这一点,是因为它讨论了我不知道的gotcha。它不是gotcha,而是你必须理解所有的东西都是渴望的,除了惰性序列,以及在它们上工作的函数。“或”短路,因为它是一个宏,所以会扩展到。如果它是一个函数,它将计算它的参数。相反,它宏扩展为if,这是一种特殊形式和短路。
(or (simple-function args)
(complex-function args)
(too-lazy-to-optimize-this-function args))
user=> (or true (do (println "hello") true))
true
user=> (or false (do (println "hello") true))
hello
true
(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