Ich versuche, einen einfachen Interpreter von einem Transformer-basierten Monad-Stack auf freiere Effekte umzuschreiben, aber ich stehe vor Schwierigkeiten, meine Absicht dem GHC-Typ-System mitzuteilen.Wie komponiere ich 'freiere' Effekte in Haskell?
Ich verwende derzeit nur die State
und Fresh
Effekte. Ich bin mit zwei Zuständen und meine Wirkung Läufer sieht wie folgt aus:
runErlish g ls = run . runGlobal g . runGensym 0 . runLexicals ls
where runGlobal = flip runState
runGensym = flip runFresh'
runLexicals = flip runState
Hinzu kommt, habe ich eine Funktion FindMacro mit dieser Art definiert:
findMacro :: Members [State (Global v w), State [Scope v w]] r
=> Arr r Text (Maybe (Macro (Term v w) v w))
All dies bisher funktioniert perfekt fein. Das Problem kommt, wenn ich versuche, macroexpand2
zu schreiben (na ja, macroexpand1, aber ich bin vereinfacht es so ist die Frage leichter folgen):
macroexpand2 s =
do m <- findMacro s
return $ case m of
Just j -> True
Nothing -> False
Dies erzeugt den folgenden Fehler:
Could not deduce (Data.Open.Union.Member'
(State [Scope v0 w0])
r
(Data.Open.Union.FindElem (State [Scope v0 w0]) r))
from the context (Data.Open.Union.Member'
(State [Scope v w])
r
(Data.Open.Union.FindElem (State [Scope v w]) r),
Data.Open.Union.Member'
(State (Global v w))
r
(Data.Open.Union.FindElem (State (Global v w)) r))
bound by the inferred type for `macroexpand2':
(Data.Open.Union.Member'
(State [Scope v w])
r
(Data.Open.Union.FindElem (State [Scope v w]) r),
Data.Open.Union.Member'
(State (Global v w))
r
(Data.Open.Union.FindElem (State (Global v w)) r)) =>
Text -> Eff r Bool
at /tmp/flycheck408QZt/Erlish.hs:(79,1)-(83,23)
The type variables `v0', `w0' are ambiguous
When checking that `macroexpand2' has the inferred type
macroexpand2 :: forall (r :: [* -> *]) v (w :: [* -> *]).
(Data.Open.Union.Member'
(State [Scope v w])
r
(Data.Open.Union.FindElem (State [Scope v w]) r),
Data.Open.Union.Member'
(State (Global v w))
r
(Data.Open.Union.FindElem (State (Global v w)) r)) =>
Text -> Eff r Bool
Probable cause: the inferred type is ambiguous
Ok , kann ich eine Members
Anmerkung der Art hinzufügen:
macroexpand2 :: Members [State (Global v w), State [Scope v w]] r
=> Text -> Eff r Bool
Und jetzt bekomme ich diese:
Overlapping instances for Member (State [Scope v0 w0]) r
arising from a use of `findMacro'
Matching instances:
instance Data.Open.Union.Member'
t r (Data.Open.Union.FindElem t r) =>
Member t r
-- Defined in `Data.Open.Union'
There exists a (perhaps superclass) match:
from the context (Members
'[State (Global v w), State [Scope v w]] r)
bound by the type signature for
macroexpand2 :: Members
'[State (Global v w), State [Scope v w]] r =>
Text -> Eff r Bool
at /tmp/flycheck408QnV/Erlish.hs:(79,17)-(80,37)
(The choice depends on the instantiation of `r, v0, w0'
To pick the first instance above, use IncoherentInstances
when compiling the other instance declarations)
In a stmt of a 'do' block: m <- findMacro s
In the expression:
do { m <- findMacro s;
return
$ case m of {
Just j -> True
Nothing -> False } }
In an equation for `macroexpand2':
macroexpand2 s
= do { m <- findMacro s;
return
$ case m of {
Just j -> True
Nothing -> False } }
Ich wurde auf IRC aufgefordert, forall r v w.
zu versuchen, was keinen Unterschied machte. Aus Neugierde versuchte ich IncoherentInstances
beim kompilieren dieser Code (ich wollte nicht eine Gabel von freier und spielen) um zu sehen, ob es vielleicht einen Hinweis geben würde, was los war. Es hat nicht:
Could not deduce (Data.Open.Union.Member'
(State [Scope v0 w0])
r
(Data.Open.Union.FindElem (State [Scope v0 w0]) r))
arising from a use of `findMacro'
from the context (Members
'[State (Global v w), State [Scope v w]] r)
bound by the type signature for
macroexpand2 :: Members
'[State (Global v w), State [Scope v w]] r =>
Text -> Eff r Bool
at /tmp/flycheck408eru/Erlish.hs:(79,17)-(80,37)
The type variables `v0', `w0' are ambiguous
Relevant bindings include
macroexpand2 :: Text -> Eff r Bool
(bound at /tmp/flycheck408eru/Erlish.hs:81:1)
Note: there are several potential instances:
instance (r ~ (t' : r'), Data.Open.Union.Member' t r' n) =>
Data.Open.Union.Member' t r ('Data.Open.Union.S n)
-- Defined in `Data.Open.Union'
instance (r ~ (t : r')) =>
Data.Open.Union.Member' t r 'Data.Open.Union.Z
-- Defined in `Data.Open.Union'
In a stmt of a 'do' block: m <- findMacro s
In the expression:
do { m <- findMacro s;
return
$ case m of {
Just j -> True
Nothing -> False } }
In an equation for `macroexpand2':
macroexpand2 s
= do { m <- findMacro s;
return
$ case m of {
Just j -> True
Nothing -> False } }
Also, das ist, wo mein Verständnis von freier Interna abläuft und ich habe Fragen:
- Warum gibt es eine überlappende Instanz? Ich verstehe nicht, woher das kommt.
- Was macht InkoherentInstances eigentlich? Autoselection klingt sehr wahrscheinlich schwer zu debuggende Fehler.
- Wie nutze ich findMacro innerhalb einer anderen Funktion?
Prost!
Ihre Antwort auf 3 ist nicht wirklich der Grund, warum dieses bestimmte Beispiel fehlschlägt (obwohl dies eine sehr vollständige Erklärung einer anderen allgemeinen Fallstrick ist) - in diesem Fall z. '\ x -> fromJust <$> findMacro x' Typ überprüft ohne zusätzliche Anmerkungen, während z. '\ x -> const True <$> findMacro x' nicht - das Problem ist, dass im OP-Beispiel der Rückgabewert (' Bool') die Typvariablen nicht erwähnt, was sie (per Definition) amüsant macht. In MTL gibt es einen fundep, so dass die Tyvars auch dann nicht mehrdeutig sind (d. H. "Const True <$> get" ist in Ordnung), aber das ist mit freierem nicht möglich. – user2407038
@ user2407038 Ich glaube nicht. 'macroexpand2' scheitert vor der Mehrdeutigkeitsprüfung, und wir haben den 'Eff r Bool'-Rückgabetyp, und alle Abhängigkeiten können potentiell aus' r 'berechnet werden, so dass es keine unmittelbare Mehrdeutigkeit gibt. –
@ user2407038 hier ist ein [kleines Beispiel] (http://lpaste.net/177990) mit einer ähnlichen Fehlermeldung wie im OP. –