Tapez erreur tout en essayant de mettre en œuvre la fonction (>> =) afin de créer un transformateur de monade personnalisé

StackOverflow https://stackoverflow.com/questions/2661895

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.

Était-ce utile?

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 am (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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top