Erlangでfizzbuzz

  • 7
    Like
  • 2
    Comment

Erlang勉強中です。逐次プログラミングを一通り勉強したのでfizzbuzzやってみました。
これが正攻法かどうかは謎ですが、一例として自分と同じ初学者の参考になればと思います。

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

%% list:fizzbuzzしたリストを返却、out:fizzbuzzした結果を都度出力
%% 1~Nまでの数値リストをfizzbuzz
run(list, N) when is_integer(N) ->
    NumList = make_list(N),
    fizzbuzz(NumList);
run(out, N) when is_integer(N) ->
    NumList = make_list(N),
    fizzbuzz2(NumList);
run(_, _) -> io:format("e.g. : run(out, ~p)~n", [10]).

%% Start~Endまでの数値リストをfizzbuzz
run(list, Start, End) when is_integer(Start), is_integer(End) ->
    NumList = make_list(Start, End),
    fizzbuzz(NumList);
run(out, Start, End) when is_integer(Start), is_integer(End) ->
    NumList = make_list(Start, End),
    fizzbuzz2(NumList);
run(_, _, _) -> io:format("e.g. : run_fizzbuzz(out, ~p, ~p)~n", [5, 10]).

% 引数が2つの場合1~nまで、3つの場合n~mまでの数値リストを作成する
% 初期値sが与えられている場合はs~nまでのリストを作成する。
make_list(MaxNum) -> make_list(1, MaxNum, []).
make_list(MinNum,MaxNum) -> make_list(MinNum, MaxNum, []).
make_list(I, Max, List) when I =< Max-> make_list(I + 1, Max, [I|List]);
make_list(I, Max, List) when I > Max -> lists:reverse(List).

%% 受け取ったリストをfizzbuzz変換したリストを返す
fizzbuzz(NumList) -> fizzbuzz(NumList, []).
fizzbuzz([H|T], Result) -> 
    case {H rem 3, H rem 5} of
        {0,0} -> fizzbuzz(T, [fizzbuzz|Result]);
        {0,_} -> fizzbuzz(T, [fizz|Result]);
        {_,0} -> fizzbuzz(T, [buzz|Result]);
        {_,_} -> fizzbuzz(T, [H|Result])
    end; 
fizzbuzz([], Result) -> lists:reverse(Result).

%% 受け取った数値リストを順にfizzbuzz出力する
fizzbuzz2([H|T]) ->
    case {H rem 3, H rem 5} of
        {0,0} -> io:format("~p:fizz buzz~n", [H]);
        {0,_} -> io:format("~p:fizz~n", [H]);
        {_,0} -> io:format("~p:buzz~n", [H]);
        {_,_} -> io:format("~p~n", [H])
    end, fizzbuzz2(T);
fizzbuzz2([]) -> io:format("End~n").

実行結果

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

書いた後に気づいたんですが、「Learn You Some Erlang for Great Good!」によると、
caseを下のように使用するのは読んでいる人を驚かせるらしいです。

case {A,B} of
    Pattern Guards -> ...
end.

 
追記:
コメントでlists:seq/2を教えていただいたので修正してみました。

修正版fizzbuzz

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

%% list:fizzbuzzしたリストを返却、out:fizzbuzzした結果を都度出力
%% 1~Nまでの数値リストをfizzbuzz
run(list, N) when is_integer(N), N > 0 -> fizzbuzz(lists:seq(1, N));
run(out, N) when is_integer(N), N > 0-> fizzbuzz2(lists:seq(1, N));
run(_, _) -> io:format("e.g. : run(out, ~p)~n", [10]).

%% From~Toまでの数値リストをfizzbuzz
run(list, From, To) when is_integer(From), is_integer(To), From =< To ->
    fizzbuzz(lists:seq(From, To));
run(out, From, To) when is_integer(From), is_integer(To), From =< To ->
    fizzbuzz2(lists:seq(From, To));
run(_, _, _) -> io:format("e.g. : run_fizzbuzz(out, ~p, ~p)~n", [5, 10]).

%% 受け取ったリストをfizzbuzz変換したリストを返す
fizzbuzz(NumList) -> fizzbuzz(NumList, []).
fizzbuzz([H|T], Result) ->
    case {H rem 3, H rem 5} of
        {0,0} -> fizzbuzz(T, [fizzbuzz|Result]);
        {0,_} -> fizzbuzz(T, [fizz|Result]);
        {_,0} -> fizzbuzz(T, [buzz|Result]);
        {_,_} -> fizzbuzz(T, [H|Result])
    end;
fizzbuzz([], Result) -> lists:reverse(Result).

%% 受け取った数値リストを順にfizzbuzz出力する
fizzbuzz2([H|T]) ->
    case {H rem 3, H rem 5} of
        {0,0} -> io:format("~p:fizz buzz~n", [H]);
        {0,_} -> io:format("~p:fizz~n", [H]);
        {_,0} -> io:format("~p:buzz~n", [H]);
        {_,_} -> io:format("~p:~n", [H])
    end, fizzbuzz2(T);
fizzbuzz2([]) -> io:format("End~n").

実行結果

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