Je ne vois aucune version publiée de syntaxique dont la signature sugarSymutilise ces noms de type exacts, donc j'utiliserai la branche de développement à commit 8cfd02 ^ , la dernière version qui utilisait toujours ces noms.
Alors, pourquoi GHC se plaint-il de la fisignature de votre type mais pas de celle pour sugarSym? La documentation à laquelle vous avez lié explique qu'un type est ambigu s'il n'apparaît pas à droite de la contrainte, sauf si la contrainte utilise des dépendances fonctionnelles pour déduire le type par ailleurs ambigu à partir d'autres types non ambigus. Comparons donc les contextes des deux fonctions et recherchons les dépendances fonctionnelles.
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
Donc pour sugarSym, les types non ambigus sont sub, siget f, à partir de ceux-ci, nous devrions pouvoir suivre les dépendances fonctionnelles afin de lever l'ambiguïté de tous les autres types utilisés dans le contexte, à savoir supet fi. Et en effet, la f -> internaldépendance fonctionnelle dans SyntacticNutilise notre fpour lever l'ambiguïté fi, et par la suite la f -> sig symdépendance fonctionnelle dans ApplySymutilise notre nouvellement désambiguïsé fipour lever l' ambiguïté sup(et sig, ce qui était déjà non ambigu). Cela explique pourquoi sugarSymne nécessite pas l' AllowAmbiguousTypesextension.
Regardons maintenant sugar. La première chose que je remarque est que le compilateur ne se plaint pas d'un type ambigu, mais plutôt de superpositions d'instances:
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
Donc, si je lis bien, ce n'est pas que GHC pense que vos types sont ambigus, mais plutôt, qu'en vérifiant si vos types sont ambigus, GHC a rencontré un problème différent et distinct. Il vous indique ensuite que si vous aviez demandé à GHC de ne pas effectuer la vérification d'ambiguïté, il n'aurait pas rencontré ce problème distinct. Cela explique pourquoi l'activation de AllowAmbiguousTypes permet à votre code de se compiler.
Cependant, le problème avec les instances qui se chevauchent reste. Les deux instances répertoriées par GHC ( SyntacticN f fiet SyntacticN (a -> f) ...) se chevauchent. Curieusement, il semble que le premier d'entre eux devrait se chevaucher avec toute autre instance, ce qui est suspect. Et qu'est-ce que cela [overlap ok]signifie?
Je soupçonne que Syntactic est compilé avec OverlappingInstances. Et en regardant le code , c'est le cas.
En expérimentant un peu, il semble que GHC accepte les instances qui se chevauchent lorsqu'il est clair que l'une est strictement plus générale que l'autre:
{-# 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])
Mais GHC n'est pas d'accord avec des instances qui se chevauchent lorsque ni l'une ni l'autre n'est clairement mieux adaptée que l'autre:
{-# 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])
Votre signature de type utilise SyntacticN (a -> (a -> b) -> b) fi, et ni l'un SyntacticN f fini l' autre ne SyntacticN (a -> f) (AST sym (Full ia) -> fi)convient mieux que l'autre. Si je change cette partie de votre signature de type en SyntacticN a fiou SyntacticN (a -> (a -> b) -> b) (AST sym (Full ia) -> fi), GHC ne se plaint plus du chevauchement.
Si j'étais vous, je regarderais la définition de ces deux instances possibles et déterminer si l'une de ces deux implémentations est celle que vous voulez.
sugarSym Let, qui est(SyntacticN f (ASTF sup a -> ASTF sup (a -> b) -> ASTF sup b), Let :<: sup) => fet n'implique pas de variables de type ambiguë?