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

という感じになるらしい。どうなってるんだ……。