Clojureのマルチメソッド
Project Euler Problem 36 は、10進数表現でも2進数表現でも回文になっている(585、1001001001)のよう数字を100万以下で求めるというもの。Clojureのマルチメソッドでやってみた。オブジェクト指向のポリフォーフィズムみたいなもので、もうちょっと柔軟なものらしい。
(use 'clojure.contrib.str-utils) (defmulti palindromic class) (defmethod palindromic String [s] (= s (str-join "" (reverse s)))) (defmethod palindromic Number [n] (palindromic (.toString n))) (defn both-palindromic? [n] (and (palindromic n) (palindromic (Integer/toBinaryString n)))) (println (apply + (filter both-palindromic? (range 1000000))))
回答のフォーラムを見ていて、偶数はチェック不要だよ、だって偶数を2進数にしたら下1桁は0だし、という指摘があって、ああ、少しぐらい頭を使わないとだわとも思った。
both-palindromic?からpalindromicを呼び出しているところで、10進数のときも「(palindromic (.toString n))」としたほうが一貫性があるので、この場合、呼び出し側の自由度が高いことに意味はないかもしれないけど、マルチメソッドの基本的な使い方を試したかっただけなのでよい。
Clojureは引数の型によらず関数を呼べるので、単一の関数として関数側で場合わけを書いてもいいのだけど、それだと場合分けによる実装のディスパッチ処理と、実装の中身がグチャっと固まってしまうという問題がある、という。なるほどーと思うけど、この程度の例だと「問題」という感じもしないので実感がわかない。
そういえば、この問題をKで解くと、
+/&(&/{x~|x}'2 10_vs\:)'!_1e6
という感じになるらしい。どうなってるんだ……。