ErlangでFizzBuzz

やったー!ErlangFizzBuzzできたー!

-module(fizzbuzz).
-export([exec/0]).

% 1からNまでのリストを作る関数
seq(0) -> [];
seq(N) -> seq(N-1) ++ [N].

% 数値を対応するFizzBuzz文字列に変換する関数
num_to_fizzbuzz(N) ->
  if
    N rem 15 == 0 -> "FizzBuzz";
    N rem  5 == 0 -> "Buzz";
    N rem  3 == 0 -> "Fizz";
    true          -> integer_to_list(N)
  end.

% 数値のリストをFizzBuzz文字列のリストに変換する関数
nums_to_fizzbuzzs(Ns) -> lists:map(fun num_to_fizzbuzz/1, Ns).

% 文字列のリストを連結する関数
join(_, []) -> "";
join(Delimiter, [X|XS]) -> X ++ Delimiter ++ join(Delimiter, XS).

% 1からNまでのFizzBuzz文字列を作成する関数
fizzbuzz(N) -> join("~n", nums_to_fizzbuzzs(seq(N))).

% FizzBuzz実行
exec() ->
  io:format(fizzbuzz(100)).

新しく覚えたこと

「%」より右はコメントになる。

% コメントだよ
increment(N) -> N + 1 % 1をプラスする関数だよ


リストの連結は「++」

[1,2,3] ++ [4,5,6]. % [1,2,3,4,5,6]

文字列もリストなので「++」で連結する。

"Hello " ++ "World!". % "Hello World!"


関数の引数にパターンマッチできる。Haskellみたい。
以下は1からNまでのリストを作る関数

seq(0) -> [];              % 引数が0だったら空のリストを返す。
seq(N) -> seq(N-1) ++ [N]. % 引数が0じゃなかったらseq(N-1)の末尾にNを加えたものを返す。

引数のパターンで分けた各関数たちは「;」でつながないといけないみたいだ。


if式もパターンマッチみたいに書く。

  if
    N rem 15 == 0 -> "FizzBuzz";
    N rem  5 == 0 -> "Buzz";
    N rem  3 == 0 -> "Fizz";
    true          -> integer_to_list(N)
  end.

ifからendまでが1つの式で、条件を上から順番に評価していって最初にtrueになったところの式を評価して返す。


関数定義には1つの式しか書けない。

exec() ->
  Result = fizzbuzz(100).
  io:format(Result).

こんな風には書けない。
でも複数の式を連結して1つの式にする「,」という演算子があるので

exec() ->
  Result = fizzbuzz(100),
  io:format(Result).

っていう風に書けばいける。


無名関数は「fun」と「end.」を使って書く。

Fn = fun(N) -> N + 1 end.


名前のついた関数を値として使う時も「fun」を使う。名前だけじゃダメで引数の数まで指定してあげないといけない。

incr(N) -> N + 1.
Fn = fun incr/1.


ループがない。変数の再代入ができないのだからループ構文というのはできないとのこと。
リストを作ってlists:mapやlists: foreachでエンヤコラするしかない。

  lists:foreach(fun(N) -> io:format("~b~n", [N]) end, [1,2,3]).
  lists:map(fun(N) -> N * 2 end, [1,2,3]). % [2,4,6]