【问题标题】:Why doesn't (apply or [true false]) work in Clojure?为什么 (apply or [true false]) 在 Clojure 中不起作用?
【发布时间】:2011-02-27 12:17:57
【问题描述】:

根据我对 apply 的理解,它解包一个列表并将元素转换为函数的参数。

我看到 (apply + [1 2 3]) 按预期工作,即:它相当于 (+ 1 2 3)。

那么为什么 (apply or [true false]) 无效?它不等于(或真假)吗?

【问题讨论】:

    标签: clojure apply


    【解决方案1】:

    因为or 是宏,而不是普通函数。使用(some identity [true false])也可以达到同样的效果。

    【讨论】:

    • 啊。谢谢!你能想到任何替代方案吗?
    • (reduce #(or %1 %2) false [true false ...])
    • 我认为 some(comp first filter) 我自己,直到 Chouser 好心让我看到更复杂的现实。尝试(some :a [{:a false} {:a nil} {:a true}]),然后将some 替换为(comp first filter)
    • @Michal:很好的修正。谢谢你让我直截了当。我已经从帖子中删除了这一点,尽管我会注意任何阅读 some is 在这种特殊情况下等同于 (comp first filter) 的人——它们都做同样的事情并给出相同的结果.
    【解决方案2】:

    作为 or 的替代方法,您可以使用 (some 谓词 coll)。

    clojure.core/some ([pred coll])
    返回第一个逻辑真值 coll 中的任何 x 的 (pred x),否则 零。一个常见的习惯用法是使用集合 作为 pred,例如这将 返回 :fred 如果 :fred 在 序列,否则为零:(some #{:fred} coll)

    【讨论】:

      【解决方案3】:

      你可以尝试一些真实的吗?和假的?谓词,

      user=> (some true? [true false false]) true user=> (not (some true? [true false false])) false user=> (some false? [true false false]) true user=> (not (some false? [true false false])) false

      【讨论】:

      • 谨防虚假?! (false? nil) 尽管 nil 被认为是假的,但仍返回假。 (boolean nil) 虽然返回 false。
      【解决方案4】:

      是一个宏,不能用作值。

      创建一个匿名函数,通过 eval 在运行时扩展

      (apply #(eval (list* 'or %&)) [true false])
      

      【讨论】:

      • 因为您可以在没有宏的情况下更自然地获得相同的结果(通过执行(reduce #(or %1 %2) false ...)),这是使用eval 是一个坏主意的情况之一。恰当的例子:您的表单不像or 那样做。例如,尝试在矢量['(or) false] 上使用它。
      【解决方案5】:

      需要注意的重要事项之一是评估模型。 or 短路,因此:(or true :some random expression that never gets evaluated:) 从不评估最后一个。 or 传统上用作控制结构,如“逻辑或”。

      (f x y z)的传统模型中,对x、y和z求值,并将f应用于它们。

      在使用(apply f vec) 时,向量的内容被评估,它们被视为原样。这在符号向量中最清晰可见,在这种情况下它们不会评估它们的绑定。然而,这被混淆了,因为 Clojure 的向量创建模型与其他 lisps 有一些不同,[a b c d] 产生一个向量,其中包含符号 abc 和 @ 的评估987654330@。对比大多数 Lisps,其中#(a b c d) 不评估符号,而与评估(vector 'a 'b 'c 'd)(或实际上(apply vector '(a b c d)))相同。

      因此,即使可以应用特殊的句法形式,其结果也会具有不透明的语义。 or 首先评估它的第一个参数,如果为真,它会停止并返回它,否则它会转到第二个并重复直到最后。在 apply 的情况下,参数已经全部被评估,是否应该再评估一些?最有可能导致运行时错误?

      从实现的角度来看,如果语法也是“对象”并且需要更复杂的评估模型,那么性能会非常不利。所以它们不是在运行时解析,而是在编译时重写为编译器原语。

      但是,正是由于这个原因,当or 被逻辑使用而不是作为控制结构时,我自己发现拥有or/fand/fif/f 等可用的函数很方便,这些都是真的程序并评估所有参数,因此可以应用。

      【讨论】:

        猜你喜欢
        • 2016-09-29
        • 1970-01-01
        • 1970-01-01
        • 2021-08-08
        • 2013-04-08
        • 2021-07-02
        • 2011-09-11
        • 2020-12-25
        • 2015-10-03
        相关资源
        最近更新 更多