Geben Sie Fehler beim Versuch, die (>> =) Funktion zu implementieren, um einen benutzerdefinierten Monade Transformator zu schaffen
-
27-09-2019 - |
Frage
Ich versuche, einen Monade Transformator für ein zukünftiges Projekt zu erstellen, aber leider meine Umsetzung der Monad typeclasse der (>> =) Funktion funktioniert nicht.
Zunächst einmal ist hier die Umsetzung der zugrunde liegenden Monade:
newtype Runtime a = R {
unR :: State EInfo a
} deriving (Monad)
Hier wird die Umsetzung der Monade typeclasse erfolgt automatisch durch GHC (die GeneralizedNewtypeDeriving
Sprache Pragma verwenden).
Der Monade Transformator ist definiert als so:
newtype RuntimeT m a = RuntimeT {
runRuntimeT :: m (Runtime a)
}
Das Problem kommt von der Art, wie ich instanziieren die (>> =) Funktion der Monade typeclasse:
instance (Monad m) => Monad (RuntimeT m) where
return a = RuntimeT $ (return . return) a
x >>= f = runRuntimeT x >>= id >>= f
So wie ich es sehe, der erste >>=
läuft in der zugrunde liegenden m
Monade. Somit kehrt runRuntimeT x >>=
einen Wert vom Typ Runtime a
(rechts?). Dann wird der folgende Code, id >>=
sollte einen Wert vom Typ a
zurückzukehren. Dieser Wert wird die Weitergabe an die Funktion f vom Typ f :: (Monad m) => a -> RuntimeT m b
.
Und hier kommt die Art Problem: die Typ der f
Funktion nicht den durch die (>> =) Funktion erforderlich Typen entspricht. Jow kann ich diese kohärent machen? Ich kann sehen, warum dies nicht funktioniert, aber ich kann es nicht schaffen es in etwas functionnal zu machen.
Edit: Die Fehlermeldung:
Core.hs:34:4:
Occurs check: cannot construct the infinite type: m = RuntimeT m
When generalising the type(s) for `>>='
In the instance declaration for `Monad (RuntimeT m)'
Failed, modules loaded: none.
Vielen Dank für Ihre Hilfe, und zögern Sie keine Fehler in meiner Nachricht zu korrigieren,
Charlie P.
Lösung
Um zu folgen, was Reid Barton sagte über StateT
- hier, wie Sie RuntimeT
mit StateT
definieren würde. Die Runtime
Monade kann dann trivialerweise mit der Identität Monade definiert werden.
newtype RuntimeT m a = R {
unR :: StateT EInfo m a
}
type Runtime = RuntimeT Identity
instance Monad m => Monad (RuntimeT m) where
return = R . return
(R m) >>= f = R (m >>= unR . f)
Andere Tipps
Die übliche StateT s m
Monade sendet a
zu s -> m (a, s)
aber Sie arbeiten mit m (s -> (a, s))
statt. Ich glaube nicht, Letztere bildet eine Monade für allgemeine s
. Sind Sie sicher, dass Sie nicht nur StateT
verwenden?
Hier ist, warum ich glaube nicht, a
? m (s -> (a, s))
ist eine Monade: Um Schreib >>=
Ich brauche eine Funktion, die Argumente der Typen
m (s -> (a, s))
a -> m (s -> (b, s))
und gibt einen Wert vom Typ
m (s -> (b, s))
Die „Effekte“ (das heißt fmap (const ())
) des Ergebnisses müssen mit denen des ersten Arguments, da wir keine Möglichkeit haben, eine a
zu bekommen, um das zweite Argument zu übergeben. Da m
nur auf der Außenseite des Ergebnistypen angezeigt wird, können wir dann nicht das zweite Argument an für alles verwenden alles gibt es keine Möglichkeit, um von der m
führt es los zu werden.