【发布时间】:2011-02-27 12:17:57
【问题描述】:
根据我对 apply 的理解,它解包一个列表并将元素转换为函数的参数。
我看到 (apply + [1 2 3]) 按预期工作,即:它相当于 (+ 1 2 3)。
那么为什么 (apply or [true false]) 无效?它不等于(或真假)吗?
【问题讨论】:
根据我对 apply 的理解,它解包一个列表并将元素转换为函数的参数。
我看到 (apply + [1 2 3]) 按预期工作,即:它相当于 (+ 1 2 3)。
那么为什么 (apply or [true false]) 无效?它不等于(或真假)吗?
【问题讨论】:
因为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)。
some is 在这种特殊情况下等同于 (comp first filter) 的人——它们都做同样的事情并给出相同的结果.
作为 or 的替代方法,您可以使用 (some 谓词 coll)。
clojure.core/some ([pred coll])
返回第一个逻辑真值 coll 中的任何 x 的 (pred x),否则 零。一个常见的习惯用法是使用集合 作为 pred,例如这将 返回 :fred 如果 :fred 在 序列,否则为零:(some #{:fred} coll)
【讨论】:
你可以尝试一些真实的吗?和假的?谓词,
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
【讨论】:
或是一个宏,不能用作值。
创建一个匿名函数,通过 eval 在运行时扩展或:
(apply #(eval (list* 'or %&)) [true false])
【讨论】:
(reduce #(or %1 %2) false ...)),这是使用eval 是一个坏主意的情况之一。恰当的例子:您的表单不像or 那样做。例如,尝试在矢量['(or) false] 上使用它。
需要注意的重要事项之一是评估模型。 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] 产生一个向量,其中包含符号 a、b、c 和 @ 的评估987654330@。对比大多数 Lisps,其中#(a b c d) 不评估符号,而与评估(vector 'a 'b 'c 'd)(或实际上(apply vector '(a b c d)))相同。
因此,即使可以应用特殊的句法形式,其结果也会具有不透明的语义。 or 首先评估它的第一个参数,如果为真,它会停止并返回它,否则它会转到第二个并重复直到最后。在 apply 的情况下,参数已经全部被评估,是否应该再评估一些?最有可能导致运行时错误?
从实现的角度来看,如果语法也是“对象”并且需要更复杂的评估模型,那么性能会非常不利。所以它们不是在运行时解析,而是在编译时重写为编译器原语。
但是,正是由于这个原因,当or 被逻辑使用而不是作为控制结构时,我自己发现拥有or/f、and/f、if/f 等可用的函数很方便,这些都是真的程序并评估所有参数,因此可以应用。
【讨论】: