-
-
Save plaster/4245866 to your computer and use it in GitHub Desktop.
(use 'clojure.set) | |
(defn n-multiples [n end] (set (range 0 end n))) | |
(defn solve [] | |
(apply + (union (n-multiples 3 1000) | |
(n-multiples 5 1000)))) |
おお、本当にいらないですねseq
。修正しました。ありがとうございます。
そういえば、apply
とreduce
の件で気になってることがあったのでした。私の感覚だと、
apply
=> 要素ぜんぶ評価して渡す
reduce
=> 都度シーケンスから取り出して畳み込む
だったので、どっちも使える状況ならreduce
のほうがいいのでは?と思っていたのです。
でも、どうも試してみた感じ、apply
のときにもちゃんと遅延してるようにみえます。
(defn my-* [& ps]
(loop [ ps ps
p 1
]
(if (nil? ps)
p
(let [[x & ps] ps]
(if (zero? x)
0
(recur ps (* p x)))))))
hoge.core=> (apply my-* (concat (repeat 100000 1) [0] (repeat 1)))
0
だとすると、最終的には必ず全部シーケンスから取り出してしまうのが確定なreduce
よりも、
関数の中で引数使うかどうか選べる apply
のほうがいいのかもしれないですね。
数値のシーケンスの総和に関しては
(reduce + '(1 2 3 4 5)) ; -> (+ (+ (+ (+ 1 2) 3) 4) 5)
(apply + '(1 2 3 4 5)) ; -> (+ 1 2 3 4 5)
なので, clojure の +
がもし二引数関数なら reduce
一択なんですが, そもそも +
自体が可変長引数を受け入れる力があるので, 可変長の要素に対する対応を reduce
で強制するのではなく, +
が持っている機能 (たとえそれが内部的に reduce
と等価だとしても) を使って上げる方が, より高い方の抽象化を使っていることになっていいんじゃないか. というのが私の考えです.
ま, おっしゃっているように, で結局 +
もしくは apply
の動作は自分の好み(遅延性があるかとか)にあっているか? というのも一つの尺度ですよね. 参考になります.
@kohyama のコメントを見る前だったので,なんだか同じようなことも書いていますが,私は (apply + coll)
派ですね. > http://tnoda-clojure.tumblr.com/post/37700304493/apply-and-reduce (@ponkore 版解答のコメントに貼ったのと同じ URL)
@plaster https://gist.github.com/4245866#gistcomment-621381 の apply
/my-*
実験分かりやすくて参考になりました.apply
に渡す関数の作り方の勉強にもなりました.
distinct も大変便利ですが, 集合も直感的で良いと思います.
あ,
apply
は, 集合に対しても適用できますのでseq
は無くて大丈夫です.