Tapez erreur tout en essayant de mettre en œuvre la fonction (>> =) afin de créer un transformateur de monade personnalisé
-
27-09-2019 - |
Question
Je suis en train de créer un transformateur de monade pour un projet futur, mais malheureusement, ma mise en œuvre de la fonction de Monad typeclasse (>> =) ne fonctionne pas.
Tout d'abord, voici la mise en œuvre de la monade sous-jacente:
newtype Runtime a = R {
unR :: State EInfo a
} deriving (Monad)
Ici, la mise en œuvre de la Monade typeclasse se fait automatiquement par GHC (en utilisant le pragma de langue GeneralizedNewtypeDeriving
).
Le transformateur monade est défini comme ceci:
newtype RuntimeT m a = RuntimeT {
runRuntimeT :: m (Runtime a)
}
Le problème vient de la façon dont j'instancier (>> =) fonction du typeclasse Monad:
instance (Monad m) => Monad (RuntimeT m) where
return a = RuntimeT $ (return . return) a
x >>= f = runRuntimeT x >>= id >>= f
La façon dont je le vois, les premières courses de >>=
dans la monade m
sous-jacente. Ainsi, runRuntimeT x >>=
retourne une valeur de type Runtime a
(droit?). Ensuite, le code suivant, id >>=
, doit renvoyer une valeur de type a
. Cette valeur est transmise à la fonction f de type f :: (Monad m) => a -> RuntimeT m b
.
Et voilà le problème du type: le type de fonction f
ne correspond pas au type requis par la fonction (>> =). Jow puis-je faire de cette cohérence? Je ne vois pas pourquoi cela ne fonctionne pas, mais je ne parviens pas à le transformer en quelque chose de fonctionnel.
Edit: Le message d'erreur:
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.
Merci de votre aide, et ne pas hésiter à corriger les défauts dans mon message,
Charlie P.
La solution
Pour suivre sur de ce que Reid Barton a dit à propos StateT
- voici comment vous définiriez RuntimeT
à l'aide StateT
. La monade Runtime
peut alors être défini trivialement en utilisant la monade identité.
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)
Autres conseils
La monade habituelle StateT s m
envoie a
à s -> m (a, s)
mais vous travaillez avec m (s -> (a, s))
à la place. Je ne pense pas que ce dernier forme une monade pour s
général. Êtes-vous sûr que vous ne voulez pas seulement d'utiliser StateT
?
Voici pourquoi je ne pense pas a
→ m (s -> (a, s))
est une monade: Pour écrire >>=
je besoin d'une fonction qui prend des arguments de type
m (s -> (a, s))
a -> m (s -> (b, s))
et renvoie une valeur de type
m (s -> (b, s))
Les « effets » (à savoir fmap (const ())
) du résultat doit être ceux du premier argument, puisque nous avons aucun moyen d'obtenir un a
pour passer au second argument. Depuis m
apparaît seulement à l'extérieur du type de résultat, nous ne pouvons donc utiliser le second argument pour quoi que ce soit-il n'y aura pas moyen de se débarrasser de l'm
il introduit.