22

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

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

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

4

5 回答 5

22

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

于 2010-06-03T20:33:47.000 回答
5

作为替代您可以使用(一些谓词 coll)。

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

于 2010-06-03T20:50:59.403 回答
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

于 2010-06-03T21:09:24.803 回答
0

or是一个宏,不能用作值。

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

(apply #(eval (list* 'or %&)) [true false])
于 2010-06-04T14:33:06.753 回答
0

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

在 的传统模型中(f x y z),对 x、y 和 z 进行评估,并将 f 应用于它们。

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

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

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

但是,正是由于这个原因,当or被逻辑地使用而不是作为控制结构时,我自己发现让函数or/f、、、、等等可用,它们是真正的过程并评估它们的所有参数,因此可以应用and/fif/f

于 2010-06-05T03:50:37.753 回答