OK、これは私をしつこくしています。多種多様なインスタンスがあるので、全体を調べて、インスタンスの存在以外のソースとターゲットのタイプ間の関係を取り除きましょう。
{-# LANGUAGE OverlappingInstances, FlexibleInstances,TypeSynonymInstances,MultiParamTypeClasses #-}
class Foo a b where f :: a -> b
これで、タイプのペアをそれらの間に一致させることができます。f
たとえば、次のようになります。
instance Foo Int Int where f = (+1)
instance Foo Int Integer where f = toInteger.((7::Int) -)
instance Foo Integer Int where f = fromInteger.(^ (2::Integer))
instance Foo Integer Integer where f = (*100)
instance Foo Char Char where f = id
instance Foo Char String where f = (:[]) -- requires TypeSynonymInstances
instance (Foo a b,Functor f) => Foo (f a) (f b) where f = fmap f -- requires FlexibleInstances
instance Foo Float Int where f = round
instance Foo Integer Char where f n = head $ show n
No instance for...
これは、Ambiguous type
エラーメッセージを回避するための多くの明示的な型注釈を意味します。たとえば、できませんがmain = print (f 6)
、できますmain = print (f (6::Int)::Int)
必要な標準タイプのすべてのインスタンスを一覧表示できます。これにより、非常に多くの繰り返しが発生する可能性があります。青いタッチペーパーに火をつけて、次のことを実行できます。
instance Integral i => Foo Double i where f = round -- requires FlexibleInstances
instance Real r => Foo Integer r where f = fromInteger -- requires FlexibleInstances
注意:これは、「整数型がある場合は、この便利なラウンド関数を使用して無料でインスタンスを作成できる」という意味ではなく、「任意の型を使用するたびに、間違いなくインスタンスになる
」という意味です。ちなみに、私はこれに使っているので、あなたのタイプがそうでない限り、私たちは脱落するでしょう。」たとえば、これはインスタンスにとって大きな問題です。i
Foo Double i
i
Foo Double i
round
i
Integral
Foo Integer Char
これにより、他のインスタンスが簡単に壊れる可能性があるため、ここで入力f (5::Integer) :: Integer
すると、
Overlapping instances for Foo Integer Integer
arising from a use of `f'
Matching instances:
instance Foo Integer Integer
instance Real r => Foo Integer r
プラグマを変更して、OverlappingInstancesを含めることができます。
{-# LANGUAGE OverlappingInstances, FlexibleInstances,TypeSynonymInstances,MultiParamTypeClasses #-}
つまり、500が返されるので、より具体的なインスタンスf (5::Integer) :: Integer
を使用していることは明らかです。Foo Integer Integer
この種のアプローチは、多くのインスタンスを手作業で定義し、標準型クラスからインスタンスを作成するときに完全にワイルドになる時期を慎重に検討することで、うまくいくと思います。(あるいは、それほど多くの標準タイプはありません。そして、私たち全員が知っているnotMany choose 2 = notIntractablyMany
ように、、あなたはそれらすべてをリストすることができます。)