以下のコードを検討してください。
{-# LANGUAGE MultiParamTypeClasses,FlexibleInstances,FunctionalDependencies,UndecidableInstances,FlexibleContexts #-}
class Foo a c | a -> c
instance Foo Int Float
f :: (Foo Int a) => Int -> a
f = undefined
ghciで推定されたタイプのfを見ると
> :t f
> f :: Int -> Float
次のコードを追加すると
g :: Int -> Float
g = undefined
h :: (Foo Int a) => Int -> a
h = g
エラーが発生します
Could not deduce (a ~ Float)
ここで何が起こったのか理解できませんか?制限により、のタイプは、推定されたタイプのに示されているようにFoo Int a
制限されているはずです。h
Int -> Float
f
インスタンスを解決する前に型の統合が行われているためですか?
[アップデート]
カフェのメーリングリストでダン・ドエルが説明
答えは、fundepの実装と型族の違いはローカル制約情報であると私は信じています。Fundepsはローカル伝播を行いません。
したがって、最初の定義では、ローカルで'
Int -> a
'を提供しました。これは、GHCに受け入れられます。次に、関数の外部で'(Foo Int a) => Int -> a
'が実際にであることがわかりInt -> Float
ます。2番目の定義では、''を与えようとしていますが、GHCは、それを決定するために使用しない制約' 'を
Int -> Float
''に提供する必要があることをローカルでしか認識していません。Int -> a
Foo Int a
a ~ Float
これはfundepsに固有のものではありません。ローカル制約ルールを持つバージョンのfundepsを作成することができます(新しいタイプのファミリーのものに変換することで簡単にできます)。しかし、その違いは、重複するインスタンスが型族ではなく、fundepsでサポートされている理由でもあります。しかし、私は今はそれには入りません。
それが何を意味するのかまだわかりません。それで、まだより理解しやすい答えを探しています。