Skip to content

Instantly share code, notes, and snippets.

@plaster
Created December 9, 2012 16:18
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save plaster/4245866 to your computer and use it in GitHub Desktop.
Save plaster/4245866 to your computer and use it in GitHub Desktop.
Problem 1
(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))))
@kohyama
Copy link

kohyama commented Dec 10, 2012

revision d23e70 を見ています.
初版から大分すっきりしましたね :-)
「割らない」というのはかっこいいですね. 思いつきませんでした.
すばらしい別解だと思います.

集合を使わない書き方を参考まで.

(apply + (distinct (concat (range 0 1000 3) (range 0 1000 5))))

@plaster
Copy link
Author

plaster commented Dec 10, 2012

distinct! シーケンスだけでいいんですね!すごいシンプルです。
setに渡してしまうとどうやらぜんぶ評価されてしまう感じですが、distinctはどうやらちゃんと遅延してる?
core.clj中の定義を覗いてみてるのですが、lazy-seqがまだよくわかっていません。
https://github.com/clojure/clojure/blob/372f03e2fa63ff7c3544be82d85e8943e85e640b/src/clj/clojure/core.clj#L4514

あと、コメントありがとうございました。初版はキーワード引数使ってみたかったりとか、余分なのがいろいろありますね。

@kohyama
Copy link

kohyama commented Dec 10, 2012

distinct も大変便利ですが, 集合も直感的で良いと思います.

あ, apply は, 集合に対しても適用できますので seq は無くて大丈夫です.

@plaster
Copy link
Author

plaster commented Dec 10, 2012

おお、本当にいらないですねseq。修正しました。ありがとうございます。

そういえば、applyreduceの件で気になってることがあったのでした。私の感覚だと、
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 のほうがいいのかもしれないですね。

@kohyama
Copy link

kohyama commented Dec 10, 2012

数値のシーケンスの総和に関しては

(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 の動作は自分の好み(遅延性があるかとか)にあっているか? というのも一つの尺度ですよね. 参考になります.

@tnoda
Copy link

tnoda commented Dec 11, 2012

@kohyama のコメントを見る前だったので,なんだか同じようなことも書いていますが,私は (apply + coll) 派ですね. > http://tnoda-clojure.tumblr.com/post/37700304493/apply-and-reduce (@ponkore 版解答のコメントに貼ったのと同じ URL)

@tnoda
Copy link

tnoda commented Dec 11, 2012

@plaster https://gist.github.com/4245866#gistcomment-621381apply/my-* 実験分かりやすくて参考になりました.apply に渡す関数の作り方の勉強にもなりました.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment