Programmer's Note

コード読み書きの備忘録。

RubyとLispとClojureのコードの読みやすさ

なぜRubyは許容可能なLISPなのか - 翡翠はコンピュータに卵を生むか」という記事が面白かった。

この記事の中でサンプルコードを使って、 プログラムの読みやすさを対比させていた部分があったので、 Clojureでやってみたくなった。

Ruby
[1,2,3].map {|n| n*n }.reject {|n| n%3==1 }
LISP
(remove-if (lambda (n) (= (mod n 3) 1))
           (mapcar (lambda (n) (* n n))
                   '(1 2 3)))

(Clojure以外のLisp系言語はよく知らないが、たぶんこれはCommon Lisp)

同じことをClojureで記述してみる

Clojureのlambdaは無名関数なので、同じことをやると以下のようになる。

(remove (fn [n] (= (mod n 3) 1)) 
                (map (fn [n] (* n n))
                     [1 2 3]))

上記LISPよりかは読みやすいが、ほぼ同等だな。

リーダーマクロ#()を使ってみると。

(remove #(= (mod % 3) 1) 
        (map #(* % %)
             [1 2 3]))

ぐっと簡潔になった。 さらに、スレッディングマクロを使うと、 Rubyメソッドチェーンのように処理の流れの通りに書ける。

(->> [1 2 3]
     (map #(* % %))
     (remove #(= (mod % 3) 1)))

一行の場合

(->> [1 2 3] (map #(* % %)) (remove #(= (mod % 3) 1)))

スレッディングマクロは、かなりプログラムの読みやすさに貢献している。 慣れてしまえばこれはRubyに匹敵する読みやすさになる。

とはいえ、しょっぱなはかなり戸惑ったけどね…。