CoffeeScriptでProject Euler #1(きわめて初歩的なカリー化の利用と解説試案)

問題文

Problem 1

10未満の自然数のうち、3 もしくは 5 の倍数になっているものは 3, 5, 6, 9 の4つがあり、これらの合計は 23 になる。
同じようにして、1,000 未満の 3 か 5 の倍数になっている数字の合計を求めよ。

Solution

divisable = (n) -> (x) -> x % n == 0

div3 = divisable(3)
div5 = divisable(5)
filter = (list) -> list.filter (i) -> div3?(i) or div5?(i)
sum = (list) -> list.reduce (a, b) -> a + b

console.log sum filter [1..1000]

内包表記も捨てがたいけど、まっとうなCoffeeScriptらしい書き方なのではないのだろうか。

カリー化解説試案

例えば、剰余を判定する関数warikireru(x, n)を定義したとしよう。

warikireru = (x, n) -> x % n == 0

warikireruはxに数値、nに除数を入力する関数である。
さて、今回の問題のように除数が3および5とわかりきっている場合、warikireruを呼び出すときいちいち引数にnを渡すのは無駄なように感じる。

warikireru(10, 3) or warikireru(10, 5)

などと書くよりは、

warikireru3(10) or warikireru5(10)

と書きたいのだ。
3と5について専用の剰余判定関数を用意してみる。

div3 = (x) -> x % 3 == 0
div5 = (x) -> x % 5 == 0

引数は簡潔になったが、明らかにこれは冗長である。
定義する関数が二つだけならまだ良いが、div6, div28, div496...が欲しいなどと言われたら大変だ。
カリー化は、このようなコードが冗長化する問題を解決する際に役に立つ。たぶん。

divisable = (n) -> (x) -> x % n == 0

div3 = divisable(3)
div5 = divisable(5)

このdivisable関数は引数にnを受け取ると、「xを引数にnで割り切れるかどうかを判定する関数」を返す。これを関数の部分適用という。
つまり、divisable(3)は

div3 = (x) -> x % 3 == 0

を生成することと等価である。divisable(5)についても同様。
例があまりにも簡単なのでタイプ数は長くなったけど、こうしてめでたくコードから冗長性が取り除かれたのでした。ぱちぱち。

ところで

シンタックスハイライトはRubyで代用。くっ。