sugarSym
正確な型名を使用するための署名を持つ構文の公開されたバージョンは表示されないため、コミット8cfd02 ^で開発ブランチを使用します。これは、これらの名前を使用した最後のバージョンです。
では、なぜGHCはfi
型シグネチャのについて不平を言っているのsugarSym
ですか。リンク先のドキュメントでは、制約が関数の依存関係を使用して他のあいまいでない型から他のあいまいでない型を推論していない限り、型が制約の右側に表示されない場合はあいまいであることを説明しています。それでは、2つの関数のコンテキストを比較して、関数の依存関係を探しましょう。
class ApplySym sig f sym | sig sym -> f, f -> sig sym
class SyntacticN f internal | f -> internal
sugarSym :: ( sub :<: AST sup
, ApplySym sig fi sup
, SyntacticN f fi
)
=> sub sig -> f
share :: ( Let :<: sup
, sup ~ Domain b
, sup ~ Domain a
, Syntactic a
, Syntactic b
, Syntactic (a -> b)
, SyntacticN (a -> (a -> b) -> b) fi
)
=> a -> (a -> b) -> b
ですからためsugarSym
、非あいまいな種類がありsub
、sig
かつf
、それらから、私たちは、すなわち、文脈で使用される他のすべてのタイプを明確にするために、機能的な依存関係を追跡することができるはずsup
とfi
。そして実際、のf -> internal
機能依存関係はをSyntacticN
使用してf
を明確化しfi
、その後、f -> sig sym
機能依存関係はをApplySym
使用して新たに明確化したものfi
を明確化しますsup
(そしてsig
、これはすでに明確です)。これsugarSym
が、AllowAmbiguousTypes
拡張機能が必要ない理由です。
では、を見てみましょうsugar
。最初のI通知は、コンパイラがされていることであるではないあいまいなタイプ文句ではなく、オーバーラップインスタンスについて:
Overlapping instances for SyntacticN b fi
arising from the ambiguity check for ‘share’
Matching givens (or their superclasses):
(SyntacticN (a -> (a -> b) -> b) fi1)
Matching instances:
instance [overlap ok] (Syntactic f, Domain f ~ sym,
fi ~ AST sym (Full (Internal f))) =>
SyntacticN f fi
-- Defined in ‘Data.Syntactic.Sugar’
instance [overlap ok] (Syntactic a, Domain a ~ sym,
ia ~ Internal a, SyntacticN f fi) =>
SyntacticN (a -> f) (AST sym (Full ia) -> fi)
-- Defined in ‘Data.Syntactic.Sugar’
(The choice depends on the instantiation of ‘b, fi’)
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
したがって、私がこの権利を読んでいる場合、GHCが型があいまいであると考えるのではなく、型があいまいかどうかを確認しているときに、GHCが別の別の問題に遭遇したということです。次に、あいまいさチェックを実行しないようにGHCに指示した場合、別の問題は発生しなかったことを示しています。これにより、AllowAmbiguousTypesを有効にすると、コードをコンパイルできるようになります。
ただし、重複するインスタンスの問題は残ります。GHC(SyntacticN f fi
とSyntacticN (a -> f) ...
)でリストされた2つのインスタンスは互いに重複しています。不思議なことに、これらの最初のものは他のインスタンスと重複しているようで、疑わしいものです。そして、どういう[overlap ok]
意味ですか?
SyntacticはOverlappingInstancesでコンパイルされていると思います。そして、コードを見ると、確かにそうです。
少し実験してみると、一方が他方よりも厳密に一般的であることが明らかな場合、GHCはインスタンスが重複しても問題ないようです。
{-# LANGUAGE FlexibleInstances, OverlappingInstances #-}
class Foo a where
whichOne :: a -> String
instance Foo a where
whichOne _ = "a"
instance Foo [a] where
whichOne _ = "[a]"
-- |
-- >>> main
-- [a]
main :: IO ()
main = putStrLn $ whichOne (undefined :: [Int])
しかし、GHCは、どちらも他のインスタンスより明らかに適合性が低い場合、インスタンスが重複しても問題ありません。
{-# LANGUAGE FlexibleInstances, OverlappingInstances #-}
class Foo a where
whichOne :: a -> String
instance Foo (f Int) where -- this is the line which changed
whichOne _ = "f Int"
instance Foo [a] where
whichOne _ = "[a]"
-- |
-- >>> main
-- Error: Overlapping instances for Foo [Int]
main :: IO ()
main = putStrLn $ whichOne (undefined :: [Int])
タイプシグネチャはを使用してSyntacticN (a -> (a -> b) -> b) fi
おり、どちらSyntacticN f fi
もどちらSyntacticN (a -> f) (AST sym (Full ia) -> fi)
よりも適していません。タイプシグネチャのその部分をSyntacticN a fi
またはに変更するとSyntacticN (a -> (a -> b) -> b) (AST sym (Full ia) -> fi)
、GHCは重複について不満を言うことはなくなります。
私があなただったら、私はこれら2つの可能なインスタンスの定義を調べて、これら2つの実装のうちの1つが必要な実装であるかどうかを判断します。
sugarSym Let
が(SyntacticN f (ASTF sup a -> ASTF sup (a -> b) -> ASTF sup b), Let :<: sup) => f
ありますか?これには、あいまいな型変数が含まれ、含まれていませんか?