次へ 前へ 目次へ 佐々木将人の個人ページへ

9 Erlangにおける選択・条件分岐

基本形

-module(test).
-export([testfunc/1]).

testfunc(1) -> io.format("neko~n");
testfunc(2) -> io.format("inu~n");
testfunc(_) -> io.format("penguin~n").

※io.format("文字列~n") とすればその文字列が印刷されます。
 上記のコードをtest.erlとして保存し,コンパイルして,test.beamができていることを確認して,「test:testfunc(任意の数字).」として呼び出してください。
(コンパイルについては,対話環境とプログラムのコンパイル(Erlang編)参照)
 任意の数字が1の時だけneko,2の時だけinuが出力され,その他の数字の場合はpenguinが出力されます。

 一般的にはこのようになります。(選択・条件分岐部分だけ記述)
  関数(第1の場合) -> その処理;
  関数(第2の場合) -> その処理;
   ……
  関数(第nの場合) -> その処理.
 erlangの特徴にはパターンマッチがあるのですが,if-then-else-end的なものがないこの表記にもその特徴が現れていると言えます。「この場合はこう処理する」というのを並べるだけで,選択・条件分岐ができてしまうのです。並べる際には,最後だけ「.」で終わらせて,途中の区切りには「;」を使用します。
 なお,上の例でも示していましたが,( ) 内に何にでもマッチする「_」ではじまる変数を置くと,何にでもマッチする(だけどそのことは覚えていない)ところ,仮に一番最後の行に置かなければ,そこでパターンマッチ成立で,その下に書かれているパターンは一切検討しないことになります。「_」で始まる変数は一番最後の行に書くべきです。

when

 たとえ場合の数が何千何万になろうとも,原理的にはそれを完全に列挙できるなら,上の基本形だけで表現できることにはなります。ただし,実際にはわずか数十ですら完全に列挙するのは面倒ですし,その処理が同一のものなら「なんとかならんのか」ということになります。
 そこで,-> の前に when で始まる条件を書き,その条件を満たす場合にだけ処理を行う……ということも可能です。
 一般的にはこうなります。
  関数(第xの場合) when 条件 -> その処理.
(他にも選択・条件分岐がある場合には「.」ではなく「;」になります。)
 例えば
  testfunc(1) -> io.format("neko~n");
  testfunc(2) -> io.format("neko~n");
   ……
  testfunc(20) -> io.format("neko~n");
  testfunc(_) -> io.format("penguin~n");
 でも全然かまわないわけですが,
  testfunc(X) when X < 1 -> io.format("penguin~n");
  testfunc(X) when X =< 20 -> io.format("neko~n");
  testfunc(_) -> io.format("penguin~n").
 と書くことができます。
 さらに when 以下の条件は複数の条件を組み合わせてもよく,
  testfunc(X) when X >= 1 , X =< 20 -> io.format("neko~n");
  testfunc(_) -> io.format("penguin~n").
 でよいことになります。
 ちなみに条件が and の関係にある時は,上の例のように「,」を使いますが,or の関係にある時は「;」を使います。
  testfunc(X) when X < 1 ; X > 20 -> io.format("penguin~n");
  testfunc(_) -> io.format("neko~n").
 は,上の例と同じ結果になります。

case……of

 when と同様に,基本形だけで記述はできるけど,これを使った方が見やすくなるというものに,case……of構文があります。
 いわゆるすごいErlang本ではこのような例を出していました。

  insert(X,[]) -> [X];
  insert(X,Set) ->
   case lists:member(X,Set) of
    true -> Set;
    false -> [X|Set]
   end.

 これは,(要素,リスト) の形式で渡されたリストの中に要素が含まれていれば元のリストを返し,含まれていなければリストの先頭に要素を加えたリストを返すものです。もっともリストが空であれば,リスト中に要素がなくても「リストの先頭に要素を加えたリストを返す」ことになります。こののプログラムのロジックとは違いますが,「とりあえずXを先頭にしたリストを生成するが,Xが2つ以上ある場合には先頭のXを取り除く」動作とも言えます。
 このプログラムは,lists:member(X,Set) の結果(true(真)かfalse(偽)か)を別関数で受け取って,それをパターンマッチさせることでも実現可能ですが,別関数を使わずにcase……ofを使用した方がわかりやすいと思います。

(2023.6.2. 初版)

次へ 前へ 目次へ 佐々木将人の個人ページへ