Clojure 有短路逻辑吗?

发布于 2024-12-17 02:01:18 字数 391 浏览 2 评论 0原文

在许多语言中,如果您按照 foo() 返回 true 的方式编写某些内容

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

,则不会评估 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 也会被计算,还是会被忽略?

谢谢!

In many languages, if you write something along the lines of

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

and foo() returns true, then bar() and foobar() will not be evaluated.

Suppose I had the following Clojure code:

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

If a evaluates to true, will b and c also be evaluated, or will they be ignored?

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

我只土不豪 2024-12-24 02:01:18

既然您回答了自己的问题,请注意,尽管在您的示例中 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))

Since you answered your own question, note that though in your example b and c may not evaluated in the (or a b c) call, the let binding is evaluated before that so the too-lazy-to-optimize-this-function call is evaluated anyway. Clojure isn't as lazy as that.

To be clear: to conditionally evaluate the function calls, you need to put the expression evaluating them in the or call, basically:

(or (simple-function args)
    (complex-function args)
    (too-lazy-to-optimize-this-function args))
笑红尘 2024-12-24 02:01:18

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

user=> (or true (do (println "hello") true))
true
user=> (or false (do (println "hello") true))
hello
true

The other answers all good, but when in doubt, you can always just test it out on the REPL:

user=> (or true (do (println "hello") true))
true
user=> (or false (do (println "hello") true))
hello
true
蓝天白云 2024-12-24 02:01:18

如有疑问,请参阅文档



用法:

<前><代码>(或)
(或x)
(或 x 和下一个)

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

(强调我的。)

和<的文档/code>显示它的行为方式也相同。

When in doubt, consult the documentation:

or
macro
Usage:

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

Evaluates exprs one at a time, from left to right. If a form
returns a logical true value, or returns that value and doesn't
evaluate any of the other expressions
, otherwise it returns the
value of the last expression. (or) returns nil.

(Emphasis mine.)

The documentation for and shows it behaves in the equivalent way too.

屋檐 2024-12-24 02:01:18

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

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

As soon as I finished typing this question, I realized I could just look at the documentation for 'or'.

From the docs:
"Evaluates exprs one at a time, from left to right. If a form
returns a logical true value, or returns that value and doesn't
evaluate any of the other expressions, otherwise it returns the
value of the last expression. (or) returns nil."

夕嗳→ 2024-12-24 02:01:18

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

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

下面是在 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

Yes, Clojure does indeed have short circuit evaluation.

One interesting feature in Clojure / other Lisps is that it is also possible to extend the language with new constructs that also provide short-circuit evaluation. This can't be done using functions in most other languages since all the parameters to a function must be evaluated before the function is called.

Here's an example of a macro to implement a short-circuiting NAND function in Clojure:

(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
凤舞天涯 2024-12-24 02:01:18
if (foo() || bar() || foobar()) { /* do stuff */ }

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

(when (or (foo) (bar) (boobar)) (comment do stuff))
if (foo() || bar() || foobar()) { /* do stuff */ }

to

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

or

(when (or (foo) (bar) (boobar)) (comment do stuff))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文