はじめに
関数型ちっくにFizz Buzzをやるのってどうすればいいんだろう?と考えて作ってみました。ちなみに関数型ちっくのルールとして考えているのは、以下の2つです。
- 変数に2度代入をしてはいけない
- なるべくmapとかfilterを使ってロジックを組んでみる
- ラムダ式はできるだけ1〜2行ですませる
コード
ループ処理にmapを使っただけ
let array = R.times((i)=>i+1, 100);
let fizzBuzz = (num) =>{
if(num%3===0 && num%5===0) {
return 'Fizz Buzz';
} else if (num%3===0) {
return 'Fizz';
} else if (num%5===0) {
return 'Buzz'
} else {
return '' + num;
}
}
let result = R.map(fizzBuzz, array);
result.forEach((item)=>console.log(item));
一番最初に書いたもの。これだけでも変数に2度代入しない、という原則は守れてる。forループで無駄に変数を使うよりはマシ程度。
ifの代わりにcondを使った(2015/03/30追記)
let array = R.times((i)=>i+1, 100);
let fizz = num => num % 2 === 0;
let buzz = num => num%5 === 0;
let fizzBuzz = num => fizz(num) && buzz(num);
let func = R.cond([
[fizzBuzz, R.always('fizzBuzz')],
[fizz, R.always('fizz')],
[buzz, R.always('buzz')],
[R.T, num=> ''+num]
]);
let result = R.map(func, array);
result.forEach((item)=>console.log(item));
Ramdaのドキュメントを読んでいたら、R.condというのを見つけて脊椎反射で使ってみたくなりました。
書いた時は結構いけると思ったんですが、後から見返すと単純にmapを使ったパターンより複雑になってて全然行けてないじゃんと思いました。そして色々考えて、下のやつを思いつきました。
↑のを少しだけかっこ良くしてみた(2015/03/30追記)
let array = R.times((i)=>i+1, 100);
let divasable = div => num => num % div === 0;
let func = R.cond([
[divasable(15), R.always('fizzBuzz')],
[divasable(3), R.always('fizz')],
[divasable(5), R.always('buzz')],
[R.T, num=> ''+num]
]);
let result = R.map(func, array);
result.forEach((item)=>console.log(item));
↑のはさすがに無いわと思い、追記しました。ここまで書いたらやっとcondを使う意義が見出せた気がします。すごく自己満足ですが、divasableのところがちょっとかっこ良く書けたような気がします。でもあとから見ると、Ramda覚えたての猿みたいなコードなんだろうなあ、と思う。
最後に
fizzBuzz関数がいけてないっす。これをもう少しスマートに書く方法はないものか。見つけ次第、追記します。
2015/03/30
R.condを使った2パターンを追加しました。