電話会社エリクソンの研究所で作られた言語「Erlang」についてしばらく調べてみようと思います。読み方はたぶん"あーらん"で。

リアルタイム処理や誤り検出が可能で組込用途に使われていて、並行処理の記述も可能、 ML や Haskell、Clean などに代表される関数型プログラミング言語の一種である、 と、見た目なかなか盛りだくさんな感じ。さてさて。

ご意見・間違いの指摘等大歓迎。

落ち穂拾い (2003/05/03)

並行処理の話に入る前に、ここまでで書き残した機能を並べてみようかと。

guard

-module(sample). -export([f/3]). f(0, 0, 0) -> [0]; f(0, 0, C) -> []; f(0, B, C) -> [-C/B]; f(A, B, C) when B*B-4*A*C > 0 -> Rd = math:sqrt(B*B-4*A*C), [(-B+Rd)/(2*A), (-B-Rd)/(2*A)]; f(A, B, C) when B*B-4*A*C == 0 -> [(-B)/(2*A)]; f(A, B, C) -> [].

1> c(sample). {ok,sample} 2> sample:f( 0, 0, 0 ). [] 3> sample:f( 1, 2, 1 ). [-1.00000] 4> sample:f( 1, -6, 5 ). [5.00000, 1.00000] 5> sample:f( 1, 1, 1 ). []

２次方程式の実解を計算する関数です。まず２字や１字の係数に 0 が来たときの場合分けはよしとして、注目すべきは when というキーワード。要するに、「 パターン when 条件 -> 」 と書いておくことで、データ構造の一致に加えて更に細かい条件で分ける マッチングが可能となります。case式でももちろん使えます。 「when～」の部分をguardと呼ぶらしい。

例外処理 catch/throw/exit

1> X=1/0, X. =ERROR REPORT==== 3-May-2003::12:10:22 === Error in process <0.25.0> with exit value: {badarith,[ {erl_eval,eval_op,3},{erl_eval,exprs,4},{shell,eval_loop,2}]} ** exited: {badarith,[{erl_eval,eval_op,3}, {erl_eval,exprs,4}, {shell,eval_loop,2}]} ** 2> X=(catch 1/0), X. {'EXIT',{badarith,[{erl_eval,eval_op,3}, {erl_eval,expr,3}, {erl_eval,exprs,4}, {shell,eval_loop,2}]}}

上では、０除算エラー（badarith）のせいで実行プロセスが強制終了してます。 対して、下では catch でエラーになる式を修飾しておくことで、 エラー種別を変数Xに格納できています。

1> X=(catch 2/1), X. 2.00000

何もエラーが起きなければ素通し。

head( [H|_] ) -> H; head( [] ) -> exit( "head: empty_list" ).

1> catch sample:head( [1,2,3] ). 1 2> catch sample:head( [] ). {'EXIT',"head: empty_list"}

０除算やマッチ失敗などは言語処理系がEXITを発行しますが、 exit 関数を呼ぶと自分でエラー処理もできます。 いわゆる例外処理として使うことができますね。

head( [H|_] ) -> H; head( [] ) -> throw( "head: empty_list" ).

1> catch sample:head( [1,2,3] ). 1 2> catch sample:head( [] ). "head: empty_list"

exitの代わりにthrowを使うと、catchしたときに throwされたものが直接帰ってきます。 こっちの使いどころはイマイチわかってないのですが、 大域脱出などに使うと便利とのことです。

List comprehension

リストの内包表現。「1,2,3 のどれか１つと 1,2,3 のどれか一つ」 の２要素からなるtupleは全部で９通りあります。 これを全部格納したリストを書いてみましょう。

1> [{1,1},{1,2},{1,3},{2,1},{2,2},{2,3},{3,1},{3,2},{3,3}]. [{1,1},{1,2},{1,3},{2,1},{2,2},{2,3},{3,1},{3,2},{3,3}]

長いです。そこで、こんな書き方ができます。

1> [{X,Y} || X<-[1,2,3], Y<-[1,2,3]]. [{1,1},{1,2},{1,3},{2,1},{2,2},{2,3},{3,1},{3,2},{3,3}]

なんとなく、要素が等しい場合は除きたくなりました。

1> [{X,Y} || X<-[1,2,3], Y<-[1,2,3], X/=Y]. [{1,2},{1,3},{2,1},{2,3},{3,1},{3,2}]

「Xに[1,2,3]のどれか、Yに[1,2,3]のどれか、が入っているパターンのうち、 XとYが等しくないもの全て」のリストを作る、という作業になっています。 「 変数名 <- 式 」の形の部分を生成子(generator)と呼び、 条件式の部分をフィルタ(filter)と呼ぶそうです。

1> Xi = [1,2,3,4,5,6]. [1,2,3,4,5,6] 2> [X*Y || X<-Xi, Y<-Xi, (X+Y) rem 2 == 0]. [1,3,5,4,8,12,3,9,15,8,16,24,5,15,25,12,24,36]

サイコロを２つ振って、足して偶数になる場合の２つの目の掛け算結果のリスト。(^^;