Erlangでfizzbuzz 高階関数使ってみた。

  • 2
    Like
  • 0
    Comment

Erlang勉強継続中です。

前回は高階関数を使っていませんでした。
せっかくなので今回無理やり使ってみました。

前回のfizzbuzz:
https://qiita.com/shiro01/items/c19ff58ba1598c3adefd

ほとんど変わりませんが、今回書いたコードです。

-module(hof_fizzbuzz).
-export([run/2, run/3]).

%% out:fizzbuzz結果を都度出力、list:fizzbuzz結果のリスト作成
%% 1~Endまでの数値をfizzbuzzする
run(out, End) when is_integer(End) -> fb_out_for(End);
run(list, End) when is_integer(End) -> fb_list_for(End);
run(_, _) -> io:format("e.g. : run(out, ~p)~n", [10]).

%% Start~Endまでの数値をfizzbuzzする
run(out, Start, End) when is_integer(Start), is_integer(End) -> fb_out_for(Start, End);
run(list, Start, End) when is_integer(Start), is_integer(End) -> fb_list_for(Start, End);
run(_, _, _) -> io:format("e.g. : run(out, ~p, ~p)~n", [10, 20]).

%% 繰り返しfizzbuzz結果を出力する。
fb_out_for(0) ->  io:format("~p:~n",[0]);
fb_out_for(End) when 0 < End -> fb_out_for(1, End, fun fb_out/1).
fb_out_for(I, End) when I =< End -> fb_out_for(I, End, fun fb_out/1).
fb_out_for(End, End, F) -> F(End);
fb_out_for(I, End, F) -> F(I), fb_out_for(I+1, End, F).

%% 与えられた数値のfizzbuzz結果を出力する
fb_out(0) -> io:format("~p:~n",[0]);
fb_out(Num) -> fb_out(Num, Num rem 3, Num rem 5).
fb_out(Num, 0, 0)-> io:format("~p:~p~n",[Num, fizzbuzz]);
fb_out(Num, 0, _)-> io:format("~p:~p~n",[Num, fizz]);
fb_out(Num, _, 0)-> io:format("~p:~p~n",[Num, buzz]);
fb_out(Num, _, _)-> io:format("~p:~n",[Num]).

%% 繰り返しfizzbuzz結果のリストを作る
fb_list_for(0) -> [0];
fb_list_for(End) when 0 < End -> fb_list_for([], 1, End, fun fb_list/2).
fb_list_for(I, End) when I =< End -> fb_list_for([], I, End, fun fb_list/2).
fb_list_for(Reslut, End, End, F) -> lists:reverse(F(Reslut,End));
fb_list_for(Reslut, I, End, F) -> fb_list_for(F(Reslut, I), I+1, End, F).

%% 与えられた数値のfizzbuzz結果をリストに追加する
fb_list(Reslut, 0) -> [0|Reslut];
fb_list(Reslut, Num) -> fb_list(Reslut, Num, Num rem 3, Num rem 5).
fb_list(Reslut, _Num, 0, 0)-> [fizzbuzz|Reslut];
fb_list(Reslut, _Num, 0, _)-> [fizz|Reslut];
fb_list(Reslut, _Num, _, 0)-> [buzz|Reslut];
fb_list(Reslut, Num, _, _)-> [Num|Reslut].

実行結果

1> c(hof_fizzbuzz).
{ok,hof_fizzbuzz}
2>
2> hof_fizzbuzz:run(list, 10).
[1,2,fizz,4,buzz,fizz,7,8,fizz,buzz]
3>
3> hof_fizzbuzz:run(out, 10).
1:
2:
3:fizz
4:
5:buzz
6:fizz
7:
8:
9:fizz
10:buzz
ok
4>
4> hof_fizzbuzz:run(list, 10, 20).
[buzz,11,fizz,13,14,fizzbuzz,16,17,fizz,19,buzz]
5>
5> hof_fizzbuzz:run(out, 10, 20).
10:buzz
11:
12:fizz
13:
14:
15:fizzbuzz
16:
17:
18:fizz
19:
20:buzz
ok
6>

fb_list_for/4について
最初は以下のように実装してました。

fb_list_for(Reslut, MaxNum, MaxNum, F) ->
    Reslut_buf = F(Reslut,MaxNum),
    lists:reverse(Reslut_buf);
fb_list_for(Reslut, I, MaxNum, F) ->
    Reslut_buf = F(Reslut, I),
    fb_list_for(Reslut_buf, I+1, MaxNum, F).

大して変わらない気もしますが、どっちがいいんだろう。