何にでも手を出すのが信条、今巷で流行っているという噂の Erlang に手を出さずにおくべきか! というわけでは必ずしもないんだけど、ちょっと Erlang かじってます。
実は関数型言語を触るのは事実上初めてなので ( XSLT も一応関数型に分類されているけど、ちょっと違うしなあ)、ずいぶん戸惑いつつ、Programming Erlang あたりをせっせと読む今日この頃。
で、戸惑ったことは結構いろいろあるわけだが、「 illegal guard expression 」と頻繁に怒られてしまうことに一番参った。
これは例えば以下のように書くと出る。
X = 9. if math:sqrt(X) == 3 -> ok end.
guard というのは if や when に使う条件節のことで、この場合は math:sqrt(X) == 3 のこと。
でも何が illegal なのかわからない。 math:sqrt(X) == 3. を単独で実行したらちゃんと true が返ってくるのに……
で、下記のように直したらやっと動いてくれた。
X = 9. XX = math:sqrt(X). if XX == 3 -> ok end.
むう。if 文には関数書くなってか。
でも、次のは怒られずにちゃんと動く。
L = [1,2,3]. if length(L) == 3 -> ok end.
うむむむ。
というわけで実は guard に使ってもいい関数というのが決まっていて、それは BIFs ( built-in functions ) の一部なのであった。
http://www.erlang.org/doc/man/erlang.html にて "Allowed in guard tests" と付記されている関数がそれに当たるのだが、ネット上では一覧っぽいものが見つけられなかった( Programming Erlang なら 3.8 Guards に一覧が載っている)。
というわけで以下がその guard に使っていい関数である。
is_atom(X) is_binary(X) is_constant(X) is_float(X) is_function(X) is_function(X, N) is_integer(X) is_list(X) is_number(X) is_pid(X) is_port(X) is_reference(X) is_tuple(X) is_record(X,Tag) is_record(X,Tag,N) abs(X) element(N, X) float(X) hd(X) length(X) node() node(X) round(X) self() size(X) trunc(X) tl(X)
関数型言語に詳しくないのではずしているかもしれないが、おそらくは副作用が生じるおそれがある(BEAM が知らない = built-in ではない関数を使った)式はガードとして適切ではないということなのだろう。
ともあれ、これでもう "illegal guard expression" と怒られずに済むよ、やれやれ。