あなたはほとんどそこにいます。OverlappingInstances
と を使用すると、これを非常に簡単に行うことができますUndecidableInstances
。これはおそらく閉じた世界の種類のクラスとして意図されているため、決定不能なインスタンスはおそらく大したことではありません。
{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances
, OverlappingInstances, TypeFamilies, UndecidableInstances #-}
data Foo a = Foo a deriving Show
class Bar a b c | a b -> c where
bar :: Foo a -> Foo b -> Foo c
instance Bar x x x where
bar (Foo a) (Foo b) = Foo a
instance (u ~ ())=> Bar x y u where
bar _ _ = Foo ()
最後のインスタンスに注意してください。()
インスタンス ヘッドを配置すると、他のインスタンスよりも具体的になり、最初に一致するため、代わりにTypeFamilies
( ~
) からの型等価アサーションを使用します。私はこれをオレグから学びました。
これがどのように動作するかに注意してください。
*Main> bar (Foo 'a') (Foo 'b')
Foo 'a'
*Main> bar (Foo 'a') (Foo True)
Foo ()
*Main> bar (Foo 'a') (Foo 1)
<interactive>:16:1:
Overlapping instances for Bar Char b0 c0
arising from a use of `bar'
Matching instances:
instance [overlap ok] u ~ () => Bar x y u
-- Defined at foo.hs:13:10
instance [overlap ok] Bar x x x -- Defined at foo.hs:9:10
(The choice depends on the instantiation of `b0, c0'
To pick the first instance above, use -XIncoherentInstances
when compiling the other instance declarations)
In the expression: bar (Foo 'a') (Foo 1)
In an equation for `it': it = bar (Foo 'a') (Foo 1)
<interactive>:16:20:
No instance for (Num b0) arising from the literal `1'
The type variable `b0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Note: there are several potential instances:
instance Num Double -- Defined in `GHC.Float'
instance Num Float -- Defined in `GHC.Float'
instance Integral a => Num (GHC.Real.Ratio a)
-- Defined in `GHC.Real'
...plus three others
In the first argument of `Foo', namely `1'
In the second argument of `bar', namely `(Foo 1)'
In the expression: bar (Foo 'a') (Foo 1)
また、GHC 7.8 では、閉じた型ファミリにアクセスできるようになると思いますが (これは私の興味に関連しているため)、これをより適切な方法で処理できるようになりますが、詳細は少し混乱します。