多相性と書き換え可能データ

let で名前の付けられる式が値でない場合,多相性に制約がつくことがある。値でないとはたとえば参照などだ。

 # let x = ref [];;
 val x : '_a list ref = {contents = []}

x は参照で,中身は空のリストだ。空だから何のリストでもいい(多相)はずで,型も '_a となっている。ここで1をコンスしてみる。

 # 1 :: !x;;
 - : int list = [1]

当然うまくいく。x 自身を書き換えたわけではないので,まだ中身はカラリストのままだ。じゃ,今度は 'a' をコンスしてみると:

 # 'a' :: !x;;
 Characters 7-9:
   'a' :: !x;;
          ^^
 This expression has type int list but is here used with type char list

エラーになった。int のリストじゃないといけないといってる。あわてて x の型を確認してみると:

 # x;;
 - : int list ref = {contents = []}

int list への参照に変わってしまっている。

どういう訳なのか理解できないのだけど,はじめ多相的だったものが,いったん int list として評価されたことで型が確定してしまった,ということだろうか。少なくとも現象としてはそういうことらしい。

ちなみに,参照ではなくただの空リストなら問題ない。

 # let y = [];;
 val y : 'a list = []
 # 1 :: y;;
 - : int list = [1]
 # 'a' :: y;;
 - : char list = ['a']