プログラミング言語II講義ノート/国島丈生(t.kunishi@gmail.com)

4. 組とリスト

プログラミング言語には、既存の型から新たな型を作る機能がある。このことを型構成子(type constructor)という。例えばCには次のような型構成子がある。
MLには、Cよりも強力な型構成子が用意されている。ここでは、そのうち最も重要な組(tuple)とリスト(list)について述べる。

組は、2つ以上の式の並びである。これらの式の型は異なっていてもよい。Cの構造体と似た概念であるが、構造体と異なり、それぞれの式には名前(メンバ名)はなく、組の中で出現した順番で区別される。

val t = (4, 5.0, "six");
val t = (4, 5.0, "six") : int * real * string

MLからの応答に注意されたい。(4, 5.0, "six")の型がint * real * stringという型であると言っている。このような型のことを積型(product type)という。積型の記法の定義は以下のようになる。

T1, T2, …, Tkを型とするとき、T1 * T2 * … * Tkは積型であり、その値は組(v1, v2, …, vk)である。ただしvi (i = 1, 2,…, k)の型はTiである。

積型構成子 * では、結合則が成り立たない。つまり、以下の2つの式はまったく異なる型である。

組tのi番目の要素を得るには、関数 #i を用いる。

val t = (4, 5.0, "six");
val t = (4, 5.0, "six") : int * real * string
#1(t);
val it = 4 : int
#3(2.0, 3, true);
val it = true : bool

リスト

0個以上の同じ型の式の並びをリスト(list)という。例えば [1, 2, 3] は整数のリストである。組と異なり、要素がすべて同じ型でなければエラーになる。

[1, 2, 3];
val it = [1,2,3] : int list
["a"];
val it = ["a"] : string list
[#"a", #"b", "c"];
Error: operator and operand don't agree [tycon mismatch]
  operator domain: char * char list
  operand:         char * string list
  in expression:
        #"b" :: "c" :: nil

型Tに対し、T型の式を要素とするリストの型は、Tに型構成子listを適用して得られる型T listである。

リストの記法、演算子

いずれも極めて重要である。
リストの連結、コンスは右結合の演算子である。例えば1::2::3::nilは1::(2::(3::nil))の意味となる。

練習問題

  1. 次の型を持つ式の例を示せ。
    1. (int * char) * string * int
    2. bool list
  2. 次の式の型を示せ。
    1. (3, 6.0, [1, 2])
    2. [(4, "a"), (5, "b"), (6, "c")]
  3. 次の式の値を示せ。
    1. #2(3, 4, 5)
    2. tl([3, 4, 5])
    3. "c" :: ["a", "t"]
  4. 次の式の型を示せ。
    1. (1.5, ("3", [4, 5]))
    2. [[1, 2], nil, [3]]
  5. 次の型を持つ式の例を示せ。
    1. (int * char) list
    2. string list * (int * (real * string)) * int