Skip to content

Instantly share code, notes, and snippets.

@plaster
Last active February 18, 2017 06:52
Show Gist options
  • Save plaster/4357479 to your computer and use it in GitHub Desktop.
Save plaster/4357479 to your computer and use it in GitHub Desktop.
Project Euler Problem 16 solution in Clojure
;;;; Project Euler Problem 16 solution
;;;; http://projecteuler.net/problem=16
(use 'clojure.test)
(import 'java.math.BigInteger)
;; Character/digit usage from: https://gist.github.com/4276901
(def solve
(comp (partial apply +)
(partial map #(Character/digit ^char % 10))
str
#(. (BigInteger. "2") pow %)
;; no reflection warnings at this method call. really?
;; cf. #(. % pow %2) => reflection warning "call to pow can't be resolved."
))
(is (= 26 (solve 15)))
(is (= 1366 (solve 1000)))
@kohyama
Copy link

kohyama commented Dec 28, 2012

@ypsilon-takai さん
「文字列化すれば文字のシーケンスが手に入るので...」という方法でなく, 数値のまま処理するとすれば, 御解答は模範的ですね.
言われてみればその方が普通のような気がします.

@tnoda さん
同じく lazy-seq 版, いいですね.
個人的に遅延評価と再帰で書くのは好きです.

目的は和なので reverse しなくても良いのですが, ヘルパー関数 digits として外に出したので, 少し汎用的に上の桁から順に返すようにしたのだと推測します.
digits* の「下の桁から一桁ずつの数値のシーケンスを返す関数」という仕様を, 名前や doc-string やコメントで, 伝える工夫をして reverse はしないというのもありかもしれません.

局所性の高い名前は defn-def ^:private を使って, 名前空間の外に export されないようにする, というのは良い習慣ですね.
見習いたいです.

@plaster
Copy link
Author

plaster commented Jan 3, 2013

@ypsilon-takai さんの指摘どおり、この問題なら数値のまま解くのが自然ですね。文字列化するにも内部的にはmodとquotしてるでしょうから、実行効率もよさそうな気がします。

@tnoda さんの lazy-seq わかりやすくて素敵です。
別のところで話題になっていた気がしますが、再帰のどこに lazy-seq を入れるか悩みどころです。
ほとんど好みの問題のような気もするのですが、(cons (rem x 10) (lazy-seq (digits* (quot x 10)))) のように書きたくなります。

  • 全体をlazy-seq にすると、先頭の要素すら、とり出されるまで計算されない
    ** 一方で、先頭の要素を取り出すだけで再帰呼び出しが1段進んで、 (pos? x) は評価される
    VS
  • 再帰呼び出しだけを lazy-seq にすると、先頭の要素を取り出しただけでは他の計算は何も起きない
    ** ただし、先頭の要素の (rem x 10) は即座に評価される

徹底するならいっそ、if の外にまで lazy-seq を出してもいいのかも? しれません。

真面目にトレードオフを考える必要がある場面があるとしたらどういうときなのか、もうちょっと考えてみます。

あと、 pos? みたいな基本的な関数をちゃんと使えるようにしたいですね。覚えます。

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