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)についても同様。
例があまりにも簡単なのでタイプ数は長くなったけど、こうしてめでたくコードから冗長性が取り除かれたのでした。ぱちぱち。