Ich sehe keine veröffentlichte Version der Syntaktik, deren Signatur sugarSym
genau diese Typnamen verwendet. Daher verwende ich den Entwicklungszweig bei Commit 8cfd02 ^ , der letzten Version, in der diese Namen noch verwendet wurden.
Warum beschwert sich GHC über die fi
Signatur in Ihrem Typ, aber nicht über die für sugarSym
? In der Dokumentation, auf die Sie verlinkt haben, wird erläutert, dass ein Typ nicht eindeutig ist, wenn er nicht rechts von der Einschränkung angezeigt wird, es sei denn, die Einschränkung verwendet funktionale Abhängigkeiten, um den ansonsten nicht mehrdeutigen Typ von anderen nicht mehrdeutigen Typen abzuleiten. Vergleichen wir also die Kontexte der beiden Funktionen und suchen nach funktionalen Abhängigkeiten.
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
Also für sugarSym
die nicht-mehrdeutig Typen sind sub
, sig
und f
, und von denen , sollten wir in der Lage sein, funktionale Abhängigkeiten zu folgen , um alle anderen Arten im Kontext verwendet eindeutig zu machen, nämlich sup
und fi
. Und tatsächlich verwendet die f -> internal
funktionale Abhängigkeit in SyntacticN
unsere f
, um unsere zu disambiguieren fi
, und danach die f -> sig sym
funktionale Abhängigkeit in ApplySym
verwendet unsere neu eindeutige, um fi
zu disambiguieren sup
(und sig
, was bereits nicht mehrdeutig war). Das erklärt also, warum sugarSym
die AllowAmbiguousTypes
Erweiterung nicht erforderlich ist .
Schauen wir uns jetzt an sugar
. Das erste, was mir auffällt, ist, dass sich der Compiler nicht über einen mehrdeutigen Typ beschwert, sondern über überlappende Instanzen:
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
Wenn ich das richtig lese, ist es nicht so, dass GHC denkt, dass Ihre Typen mehrdeutig sind, sondern dass GHC bei der Überprüfung, ob Ihre Typen mehrdeutig sind, auf ein anderes, separates Problem gestoßen ist. Es sagt Ihnen dann, dass, wenn Sie GHC angewiesen hätten, die Mehrdeutigkeitsprüfung nicht durchzuführen, dieses separate Problem nicht aufgetreten wäre. Dies erklärt, warum das Aktivieren von AllowAmbiguousTypes das Kompilieren Ihres Codes ermöglicht.
Das Problem mit den überlappenden Instanzen bleibt jedoch bestehen. Die beiden von GHC ( SyntacticN f fi
und SyntacticN (a -> f) ...
) aufgelisteten Instanzen überschneiden sich. Seltsamerweise scheint sich die erste davon mit jeder anderen Instanz zu überschneiden, was verdächtig ist. Und was heißt [overlap ok]
das?
Ich vermute, dass Syntactic mit OverlappingInstances kompiliert wurde. Und wenn man sich den Code ansieht , tut es das tatsächlich.
Wenn man ein bisschen experimentiert, scheint es, dass GHC mit überlappenden Instanzen einverstanden ist, wenn klar ist, dass eine streng allgemeiner ist als die andere:
{-# 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])
Aber GHC ist nicht in Ordnung mit überlappenden Fällen, in denen keiner eindeutig besser passt als der andere:
{-# 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])
Ihre Typensignatur wird verwendet SyntacticN (a -> (a -> b) -> b) fi
und passt weder SyntacticN f fi
noch SyntacticN (a -> f) (AST sym (Full ia) -> fi)
besser als die andere. Wenn ich diesen Teil Ihrer Typensignatur in SyntacticN a fi
oder ändere, SyntacticN (a -> (a -> b) -> b) (AST sym (Full ia) -> fi)
beschwert sich GHC nicht mehr über die Überlappung.
Wenn ich Sie wäre, würde ich mir die Definition dieser beiden möglichen Instanzen ansehen und feststellen, ob eine dieser beiden Implementierungen die gewünschte ist.
sugarSym Let
, bei dem es(SyntacticN f (ASTF sup a -> ASTF sup (a -> b) -> ASTF sup b), Let :<: sup) => f
sich um mehrdeutige Typvariablen handelt und nicht?