読者です 読者をやめる 読者になる 読者になる

組とパターンマッチ

組 : 複数のデータを並べて1つのデータにしたもの。

今までのような単純な数値や、文字列ではなく
それらを組み合わせて1つのデータを形成する。

2次元平面上の座標のような感じで

# (3.14, 2.71) ;;
- : float * float = (3.14, 2.71)

という、float * float型のデータを作ることが出来る。
※組の型は「*」で要素の型をつないだ形式で表す。


組の要素は違う型同士、3つ以上、ネストもおk。

# (3.14, true) ;;
- : float * bool = (3.14, true)

# (3, "string", false) ;;
- : int * string * bool = (3, "string", false)

# ((3.14, 2.71), "string") ;;
- : (float * float) * string = ((3.14, 2.71), "string")

パターンマッチ:複数のデータからデータを取り出す

match1 with
  パターン ->2

のように書くと

  1. 式1を実行
  2. 式1の実行結果をパターンと照合する。
  3. 照合結果を使って式2を実行する
# match (3, 5) with
    (a, b) -> a + b ;;
- : int = 8;

上のプログラムでは(3, 5)というint * int型のデータから(a, b)の様な
2つの値の組を表すパターンを取り出して、それらを加えた結果を返すということになる。
※ここで使用されているa、bの様な変数はパターン変数と呼ばれる。

パターンを取り出すと聞いて、思わず

# match (3, 5, 6) with
    (a, b) -> a + b ;;

とやると、怒られる。

# match (3, 5, 6) with
    (a, b, c) -> a + b ;;

ってことか。

関数で

上では、組を作ったすぐ後にパターンマッチで値を取り出しているが
実際には、組を作るのと、その中の要素を取り出すのは別の場所で行われるのが普通。
ということで、関数を作ってみる。

# let add pair = match pair with
    (a, b) -> a + b ;;
# add (3, 5) ;;
- : int = 8

add関数は(a[int型], b[int型])という組を引数として受け取らないといけない。


実は以下の様にも書ける。

# let add (a, b) = a + b ;;

悲しいかなこっちの方がなんとなく落ち着く書き方である。
※この書籍では系統的なプログラミングを学ぶという観点から使われない。


ただ、(a, b)のような組を受け取って、足して返すみたいなことは

# let add a b = a + b ;;

と、普通の関数を定義してやれば出来てしまうので
いまいち、ありがたみがわからない。


基本的な使い分け方としては

  • 変数を引数とした関数 : 引数の値がお互いに関係ない場合。
  • 組を引数とした関数 : 引数の値が意味的に1つにまとめられる場合。


例えば、「名前-成績」とか「x座標-y座標」などは、組を引数として定義した方が良い。

補足

2つの組を引数として受け取る場合。

(* 2組の座標を受け取り、その中点を返す *)
(* middle : float * float -> float * float -> float * float *)
let middle point1 point2 = match point1 with
  (x1, y1) -> match point2 with
    (x2, y2) -> ((x1 +. x2) /. 2.0 , (y1 +. y2) /. 2.0)


組の様に構造を持つデータを扱う関数を考える場合は
ほぼ、matchを使ってデータを取り出す=関数はmatch文で始まる。


入力が決まったら必然的に決まる関数本体の形をテンプレートと呼び
関数本体を作る前には、テンプレートを作っておくと楽。