2012-01-20 5 views
5

Ceci est ma première connaissance avec Monad Transformers, donc la réponse pourrait être évidente. Disons que je suis dans un bloc do de type StateT MyMonad MyType, je veux qu'une autre fonction du même type modifie l'état et renvoie une valeur de type MyMonad MyType. Comment puis-je y parvenir? Je pense que les exemples here le montrent dans guessSession, mais je n'arrive pas à comprendre comment l'appliquer!Résultat de Monad Transformateur Monad

+1

Si vous ne connaissez pas Hoogle: http: // www.haskell.org/hoogle – jberryman

Répondre

9

Si vous souhaitez utiliser la monade sous-jacente dans un transformateur de monade, vous pouvez utiliser lift:

lift :: (MonadTrans t, Monad m) => m a -> t m a 

Dans ce cas, t est StateT MyState et m est MyMonad. Ainsi, par exemple:

foo :: StateT MyState MyMonad MyType 
foo = do 
    modify $ \s -> s+1 
    lift $ doSomethingInMyMonad 42 

transformateurs Monad ne sont pas « en couches sur » dans le sens que vous souhaitez retourner une valeur de type MyMonad MyType à l'intérieur; c'est une transformation plus littérale : ils transforment une monade en une nouvelle qui a la capacité d'exécuter des actions dans la monade transformée. Ainsi, vous pouvez considérer StateT s m comme la monade régulière State s, sauf que vous pouvez également utiliser lift pour exécuter des actions de virage dans m en actions dans StateT s m.

Si vous utilisez les transformateurs standards Monad Transformer Library (mtl) comme StateT, ReaderT, etc., vous n'avez pas réellement d'utiliser lift; des choses comme modify et ask fonctionnent en toute monad avec le bon transformateur quelque part dans la pile. (Une pile est juste une tour de monades transformées, comme StateT s (ReaderT r IO).)

De plus, si vous avez une grande pile avec IO au fond, il y a une fonction pratique pour soulever une action IO un nombre quelconque de couches:

liftIO :: (MonadIO m) => IO a -> m a 

Ainsi liftIO (putStrLn "Hello, world!") œuvres dans IO, StateT Int IO, ContT r (WriterT [String] IO), et ainsi de suite.

(Comme une note supplémentaire, foo ici est pas vraiment une fonction, un terme plus précis est l'action ou calcul.)

+0

Je pense que je comprends. Juste pour être parfaitement clair. Imaginez que j'ai fait un <- doSomethingInMyMonad 42 avant d'ajouter StateT. Maintenant, je fais un <- lift $ doSomethingInMyMonad 42. Correct? – aelguindy

+0

@aelguindy: Ouais! Si vous avez une section de code qui utilise simplement MyMonad, vous pouvez aussi lever un bloc entier: 'lift $ do ...'. – ehird

+0

Merci! Je ne sais pas si c'est le bon endroit à demander, mais y a-t-il un équivalent à lever mais avec 2 arguments, lift2? * Question stupide! * Trouvé la réponse – aelguindy