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']