読者です 読者をやめる 読者になる 読者になる

Clojure - someはfalseじゃなくてnilを返す

clojure

JavaScriptのArray.some感覚で使っていたら間違えたのでメモ。

Returns the first logical true value of (pred x)

ClojureDocs

Returns the first logical true value of (pred x) for any x in coll,
else nil. One common idiom is to use a set as pred, for example
this will return :fred if :fred is in the sequence, otherwise nil:
(some #{:fred} coll)

条件に一致する場合に何を返すかはpredに依存します。
例えばtrueを返すpredならtrueです。

sample=> (some true? [false true false])
true
sample=> (some even? [1 3 4 6 7])
true

値を返す場合は、最初に一致した値が返ります。
(trueを返している場合も結局は同じことですが)

sample=> (some #(if (even? %) %) [1 3 4 6 7])
4

else nil

すべての要素がpredに失敗した場合はnilが返ります。

sample=> (some even? [1 5 7])
nil

someはpredicateではないからです。
関数名に「?」が付いていないのもそのためです。

後述のフォーラムに説明が書かれています。

一致したらtrue、一致しなかったらfalseを返したい

some-fnを使う

sample=> ((some-fn even?) 1 5 7)
false
sample=> (apply (some-fn even?) [1 5 7])
false

ただやはりpredに依存するので注意。

sample=> ((some-fn #(if (even? %) %)) 1 5 7)
nil
sample=> ((some-fn #(if (even? %) %)) 1 5 7 8)
8

not-every?やnot-any?を使う方法も良いと思います。

参考

falseを返さないことでミスったのと、
「何でsomeは?なしでnot-every?とかは?付いているんだ」と思ったことがきっかけ。

フォーラムにそのまんま書いてありました。

Is there a reason why 'some' returns "nil" instead o "false"?