非可述多相
ImpredicativeTypes
RankNTypesを含む.
6.10.1以降.
非可述多相型を許す.
一般的に, GHCは多相な関数を単相型(forallのないようなもの)でのみインスタンス化する. 例えば,
code:ip01.hs
runST :: (forall s. ST s a) -> a
id :: forall b. b -> b
foo = id runST -- Rejected
fooの定義においては,idの型をb := (forall s. ST s a) -> aに具体化するしかないが,それが許されないためfooの定義は拒否される.多相な型に具体化される多相な型変数は非可述多相と呼ばれる.
GHCの非可述多相(ImpredicativeTypes拡張によって有効化される)のサポートは極めて信用ならない.この拡張がうまく動けば, 多相型で多相的な関数を呼び,多相型上でデータ構造をパラメータ化することだってできることを意味するだろう.例えば,
code:ip02.hs
f :: Maybe (forall a. a -> a) -> Maybe (Int, Char) f (Just g) = Just (g 3, g "hello") f Nothing = Nothing
ここで,Maybe型は多相型(forall a. [a] -> [a])によってパラメータ化されていることに注意すること.
しかしながらこの拡張はとても実験的な機能であると考えられるべきであり,確実にサポートされなくなるべきである.試してもらうのは大いに結構だが,ずっと動いてくれることや今後のリリースで同じ挙動を保ち続けてくれることを当てにするのはお願いだからしないでいただきたい.詳しくはこのwikiのページを参照のこと. 非可述多相を使いたい場合,主なワークアラウンドとしてはnewtypeラッパーを用いるという手がある.前述のid runSTの例は,このワークアラウンドを使って次のように書くことができる.
code:ip03.hs
runST :: (forall s. ST s a) -> a
id :: forall b. b -> b
newtype Wrap a = Wrap { unWrap :: (forall s. ST s a) -> a }
foo :: (forall s. ST s a) -> a
foo = unWrap (id (Wrap runST))
-- Here id is called at monomorphic type (Wrap a)