束縛と一般化
恐ろしい単相性制限を解除する
NoMonomorphismRestriction
デフォルトで有効
6.8.1以降
明示的な型シグネチャがない束縛にコンパイラが単相性制限を適用しないようにする.
Letの一般化
MonoLocalBinds
6.12.1以降
デフォルトでローカルの束縛に対して多相でない型を推論する.
MLスタイルの言語は通常,let束縛またはwhere束縛の変数の型を一般化して,できるだけ多相になるようにする.MonoLocalBinds拡張を使うと,GHCは次のルールを使って,やや保守的なやり方を実行する.
変数が閉じているとは,
変数はlet束縛されている(訳注:かつ,).
次のいずれかが成り立つ,
変数が,自由な型変数を持たない明示的な型シグネチャを持っている.
その束縛群が完全に一般化されている(次の箇条書きを参照せよ).
束縛群が完全に一般化されているとは,
それぞれの自由変数はインポートされているか閉じられている.かつ,
たとえば,次の例のを考えてみよう.
code:bg01.hs
f x = x + 1
g x = let h y = f y * 2
k z = z+x
in h x + k x
ここでfは自由変数を持たないので一般化されている.そして,その束縛群は単相性制限の影響を受けない.したがって,fは閉じている.ほぼ同じ論法がgにも当てはまるが,gには1つの閉じた自由変数,すなわちfがあるという点だけ異なる.同様に,hはトップレベルに束縛されていないにもかかわらず閉じている.なぜなら,その唯一の自由変数fが閉じているからである.しかし,kは閉じていない.なぜなら,閉じていないxに言及しているからである(xが閉じていないのは、xがlet束縛されていないからである).
単相性制限の影響を受けるトップレベルの束縛は閉じておらず,そのため,言及している束縛の一般化が妨げられる可能性があることに注意せよ.
MonoLocalBinds拡張はTypeFamiliesとGADTsに含まれている.NoMonoLocalBindsを使ってそれを再びオフにすることができるが,そうすると型推論は予測しにくくなる(詳しくは論文を読んでくれ).
種の一般化
MonoLocalBindsが「どのような状況で項の型を一般化するか」((訳注:この記事内の)「Letの一般化」を参照せよ)に対して制限を加えるのと同様,MonoLocalBindsは「どのような状況で 型シグネチャの種を一般化するか」に対しても制限を加える.
code:bg02.hs
data Proxy a = Proxy
newtype Tagged s b = Tagged b
class C b where
c :: forall (s :: k). Tagged s b
instance C (Proxy a) where
c :: forall s. Tagged s (Proxy a)
c = Tagged Proxy
MonoLocalBindsが有効になっていれば,このC (Proxy a)のインスタンスは型検査を通らない.その理由は以下の通りである.cの型シグネチャが,外側のスコープの型変数aをキャプチャするため,型シグネチャは閉じていない.したがって,sの推論された種は一般化されず,その結果,cの宣言で指定された種変数kと単一化できない.これは,sに明示的な種変数を指定することで回避できる.例えば,
code:bg03.hs
instance C (Proxy a) where
c :: forall (s :: k). Tagged s (Proxy a)
c = Tagged Proxy
あるいは,
code:bg04.hs
instance C (Proxy a) where
c :: forall k (s :: k). Tagged s (Proxy a)
c = Tagged Proxy
これら2つの宣言は,Haskellの暗黙の「暗黙のforallの追加」規則により等価である(暗黙の量化を参照せよ).暗黙のforall規則は純粋に構文上のものであり,ここで説明している種の一般化とはまったく別のものである.