Ruby で関数型プログラミングもどき
上のリンク先で JavaScript を使って、オブジェクト指向プログラミングと関数型プログラミングの対比をやってあったので、Ruby に移植してみました。
課題:
http://qiita.com/stkdev/items/5c021d4e5d54d56b927c
唐揚げ弁当がいくつかあるとします。それぞれ唐揚げが複数入っています。
この中からx個の唐揚げをつまみ食いするプログラムを作りましょう。
つまみ食いはバレないようにするために、
その時点で最も唐揚げ数が多いお弁当から取るという仕様にします。
オブジェクト指向で。こんな感じですかね。
class Bento def initialize(dish, num) @dish = dish @num = num end attr_reader :num def eat @num -= 1 end def show puts @dish + @num.to_s + "個" end end order = [Bento.new("唐揚げ", 10), Bento.new("唐揚げ", 8), Bento.new("唐揚げ", 6)] 5.times do max_bento = order.inject(order.first) {|r, bento| r = (bento.num > r.num) ? bento : r} max_bento.eat puts "-------" order.each {|x| x.show} end
結果。
------- 唐揚げ9個 唐揚げ8個 唐揚げ6個 ------- 唐揚げ8個 唐揚げ8個 唐揚げ6個 ------- 唐揚げ7個 唐揚げ8個 唐揚げ6個 ------- 唐揚げ7個 唐揚げ7個 唐揚げ6個 ------- 唐揚げ6個 唐揚げ7個 唐揚げ6個
次は関数型プログラミングっぽく。元の JavaScript コードは上と同じ答えを返さないので、多少変更してあります。
order = [{dish: "唐揚げ", num: 10},
{dish: "唐揚げ", num: 8},
{dish: "唐揚げ", num: 6}]
show = ->(d) {puts d[:dish] + d[:num].to_s + "個"}
show_all = ->(data) {data.each {|x| show[x]}}
select_eating_bento = ->(data) {
data.inject(data.first) {|r, bento| r = (bento[:num] > r[:num]) ? bento : r}
}
eating_karaage = ->(data) {
data.map do |bento|
if bento.equal?(select_eating_bento[data])
{dish: bento[:dish], num: (bento[:num] - 1)}
else
bento
end
end
}
eating = ->(num, data) {
data = eating_karaage[data]
puts "-------"
show_all[data]
eating[num - 1, data] if num > 1
}
eating[5, order]
「副作用」がないようにというのが目標ですね。
どちらがわかりやすいでしょうか。
元記事は色いろコメントで怒られていますね…。