型変数の比較
Haskellの型レでは型変数同士の比較ができないぜーというお話をしたんですが、OlegさんのReversing Haskell typechecker: converting from undefined to defined のTypeEqを試したらば、できちゃいました。
So, TypeEq is total for ground types, and partial for unground types.
とか、
TypeEq cannot establish equality for ungrounded types;
とあるのでできないと思い込んでいたのだけど、その後のGHCの型検査器の変更でできるようになってしまった、ということなんだろうか?
GHC 6.6でもオッケーです。6.4は手元にないのでわからない(けど記事の日時からして多分できるんだろう)。
{-# OPTIONS -fglasgow-exts #-} {-# OPTIONS -fallow-undecidable-instances #-} {-# OPTIONS -fallow-overlapping-instances #-} {-# OPTIONS -fallow-incoherent-instances #-} {-# OPTIONS -fno-monomorphism-restriction #-} -- 無くしてみると… -- GHC 6.8 or later -- {-# LANGUAGE UndecidableInstances, OverlappingInstances, IncoherentInstances #-} -- {-# LANGUAGE NoMonomorphismRestriction #-} -- HList data s :|: ss = s :|: ss data Nil = Nil infixr 7 :|: -- 型変数を生成する gen :: (a -> ss) -> ss gen = undefined -- 最初に見つけた型変数tを 型Helloに置き換える data Hello update :: Update t Hello ls ls' => t -> ls -> ls' update = undefined -- 次のリストの型変数 a1 を… -- orig :: (Num t) => a :|: (Char :|: (t :|: (a1 :|: Nil))) orig = gen (\a -> gen (\b -> a :|: 'x' :|: 1 :|: b :|: Nil)) -- Helloに置き換える. -- test :: (Num t) => a :|: (Char :|: (t :|: (Hello :|: Nil))) -- on GHC 6.8 or later test = gen (\a -> gen (\b -> update b $ a :|: 'x' :|: 1 :|: b :|: Nil)) -- 型レ class Update t t' ls ls' | t t' ls -> ls' instance (TypeEq t l b, Update' b t t' (l:|:ls) ls') => Update t t' (l:|:ls) ls' class Update' b t t' ls ls' | b t t' ls -> ls' instance Update' HTrue t t' (l:|:ls) (t':|:ls) instance Update t t' ls ls' => Update' HFalse t t' (l:|:ls) (l:|:ls') -- from http://okmij.org/ftp/Haskell/types.html#de-typechecker data HTrue data HFalse -- literally lifted from the HList library class TypeCast a b | a -> b, b->a where typeCast :: a -> b class TypeCast' t a b | t a -> b, t b -> a where typeCast' :: t->a->b class TypeCast'' t a b | t a -> b, t b -> a where typeCast'' :: t->a->b instance TypeCast' () a b => TypeCast a b where typeCast x = typeCast' () x instance TypeCast'' t a b => TypeCast' t a b where typeCast' = typeCast'' instance TypeCast'' () a a where typeCast'' _ x = x class TypeEq' () x y b => TypeEq x y b | x y -> b where type'eq :: x -> y -> b type'eq _ _ = undefined::b class TypeEq' q x y b | q x y -> b class TypeEq'' q x y b | q x y -> b instance TypeEq' () x y b => TypeEq x y b instance TypeCast b HTrue => TypeEq' () x x b instance TypeEq'' q x y b => TypeEq' q x y b instance TypeEq'' () x y HFalse