ところで Erlang の言語仕様で個人的に気になること。
とりあえずこのみっつかな。最初のもひどいんだが、 Haskell を使っているとそれなりに感覚がマヒしてくるので(とりあえずiconvとかあるしいーや派)ひとまず脇に置くとして、関数内にローカルな定義を書けないのも、それが Erlang の流儀ならそれでよしとしようじゃない。
で、最後のことについて。たとえば member という次のような関数があるとします。
member(X, []) = false; member(X, [X|_]) = true; member(X, [_|L]) = member(X, L).
でも、この member をガードに使うことができないわけです。たとえば、メッセージを受信したいが、あらかじめ事前に、リストで渡したデータだけを受け取り、ほかのものは無視したいとする。 ML とか Haskell とかに慣れていると、自然と次のように書くことでしょう。
receiver(L) ->
receive
Msg when member(Msg, L) -> ...
end.
でもこうは書けないっつーことです。 when 以降には任意の式が置けるわけじゃないから。
……when は特別なんですよと覚えればいいじゃないって思いましたか? でもね、 Erlang では、実は if 式というのもパターンガードの集まりであるという原理がある。したがってif の条件部には任意の式は置けません。これはけっこうびっくりしませんか?
1> if
member(1, [1,2,3,4,5]) -> ok;
true -> fail
end.
** 1: illegal guard expression **
どうするかというと、こういう場合には case を使えばいい。
1> case member(1, [1,2,3,4,5]) of
true -> ok;
_ -> fail
end.
それじゃ、 receive でガードする場合はどうでしょう。ガードが成立してもしなくても処理をする場合はともかく、ガードが成立しなくて今この場では処理したくないメッセージはどうればいいんですかねー。自分で自分に send するのかしら?
receiver(L) ->
receive
Msg -> case member(Msg, L) of
true -> ...;
_ -> self() ! Msg
end
end.
もっと複雑なパターンの場合にメッセージの順番が維持されるかとかが気になるけれど、ひとまずこう書けばいいのかなー。
でもなんで、パターンガードにそんな制約を加えているんだろう。確かに、任意の関数を許すよりはパフォーマンスは上がるのかもしれないが、なんかちょっと微妙。