適用について私が理解していることから、リストをアンパックし、要素を関数の引数に変換します。
(apply + [1 2 3]) が期待どおりに機能することがわかります。つまり、(+ 1 2 3) と同等です。
では、なぜ (apply or [true false]) が無効なのでしょうか? (または true false) と同等ではありませんか?
or
はマクロであり、通常の関数ではないためです。と同じ効果が得られ(some identity [true false])
ます。
orの代わりに( some predicate coll )を使用できます。
clojure.core/some ([pred coll])
coll 内の任意の x に対して (pred x) の最初の論理真値を返し、それ以外の場合は nil を返します。一般的なイディオムの 1 つは、セットを pred として使用することです。たとえば、:fred がシーケンス内にある場合は :fred を返し、そうでない場合は nil: (some #{:fred} coll) を返します。
trueでいくつか試すことができますか?そして偽?述語、
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
ただし、注意すべき重要な点の1つは、評価モデルです。or
したがって、短絡:(or true :some random expression that never gets evaluated:)
最後を評価することはありません。or
伝統的に、「論理和」と同じくらい制御構造として使用されます。
従来のモデルでは(f x y z)
、x、y、zが評価され、fが適用されます。
(apply f vec)
ベクトルの内容の使用は評価されず、そのまま取られます。これは、シンボルのベクトルで最も明確に表示されます。このコンテキストでは、バインディングを評価しません。ただし、これは、Clojureのベクトル作成モデルが他のLispとは多少異なり、記号、、、、およびの評価を含むベクトルを生成するという事実によってわかりにくくなってい[a b c d]
ます。ほとんどのLispとは対照的で、シンボルを評価せず、評価する(または実際には)と同じです。a
b
c
d
#(a b c d)
(vector 'a 'b 'c 'd)
(apply vector '(a b c d))
したがって、特別な構文形式を適用できたとしても、その結果は不透明なセマンティクスになります。or
最初に最初の引数を評価します。trueの場合は停止して返します。それ以外の場合は2番目の引数に移動し、最後まで繰り返します。適用の場合、引数はすでにすべて評価されていますが、もう一度評価する必要がありますか?途中でランタイムエラーが発生する可能性がありますか?
実装の観点からすると、構文も「オブジェクト」であり、はるかに複雑な評価モデルが必要になると、パフォーマンスが大幅に向上します。したがって、これらは実行時に解決されるのではなく、コンパイル時にコンパイラプリミティブに書き直されます。
しかし、このため、or
制御構造としてではなく論理的に使用する場合、真のプロシージャであり、すべての引数を評価して適用できる関数、、などを使用できると便利ですor/f
。and/f
if/f
orは値として使用できないマクロです。
匿名関数を作成し、展開するか、 実行時に evalを使用します。
(apply #(eval (list* 'or %&)) [true false])