Talk:Haskell/Monad transformers

Type of main
I've just discovered that main can have in fact different type than IO, which I thought shouldn't be the case ever. I tried to copy the MaybeT and askPassphrase to a file and run it, first in ghci. But then I wanted to use runghc and put  in the file which worked fine. But adding usual type of IO to main gave an error. Adding IO (Maybe ) worked. This is the first time ever I see that main can have slightly different type, that should be explained a little further or just emphasized at this point.

Kowey's notes
I'm using this section to note my thoughts down as I struggle to understand monad transformers. Perhaps these bits and pieces can then be used to build a tutorial. Don't pay it any heed. I'll clean it up as things become clearer to me and share them with the wikibooks community.

Perhaps one useful trick to understanding this is not to think in terms of embedding one monad instead another, but of combining two monads into a third super-monad with functionality from both.

Or another way to look at is that that monad transformers are devious creatures: we talk about them as if we're running a monad inside of another, but what we're really doing is threading the so-called outer-monad through in so-called inner monad.


 * http://homepages.inf.ed.ac.uk/wadler/topics/monads.html

lift (or liftM for monads)
Ok, so you use  to lift non-monadic functions into a monad. Similarly, monad transformers are monads which provide a function  to lift functions from one monad into another. So,  isn't anything fancy; it's just the same thing as   for monads.

class MonadTrans t where lift :: Monad m => m a -> t m a

Wait a sec: why is it that all of a sudden, our lift function only takes one argument and not two?


 * It looks to me like lift is now lifting any monadic value, not just functions. Let's see here:

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


 * I'm not sure how well these unify, but hopefully this answers your question. --Ihope127 17:10, 17 February 2006 (UTC)


 * Whoops! Sorry, I didn't mean to leave these old notes lying around. I think I'm ok with   and   now (see the module page).  If you want to help me understand arrows, though, see Talk:Programming:Haskell arrows/Kowey :-D -- Kowey 23:27, 17 February 2006 (UTC)

Squeee!
Nothing serious, but today I figured out how to use the State monad (hurray for me), and I wrote a silly program using a state-monad transformer! I think I'm finally getting this stuff :-)

bottle :: StateT Int IO Int bottle = do  t <- get liftIO $ putStrLn $ show t ++ " bottles of beer on the wall!" put (t - 1) return (t - 1) countBottles :: StateT Int IO countBottles = do  n <- bottle if n == 0 then liftIO $ return else countBottles bottles :: Int -> IO (, Int) bottles = runStateT (countBottles)

Thank you, wikibooks folks!

--Tchakkazulu 20:54, 7 September 2006 (UTC)

Instance definitions
instance (Monad m) => Monad (Maybe m) where

Shouldn't this rather be:

instance Monad Maybe where

Same for List.

--gog (2007-01-18)


 * Whoops! I think the correct declaration is instance Monad (Maybe a) where Thanks for pointing this out -- Kowey 11:49, 18 January 2007 (UTC)


 * Maybe a has kind *. A monad must have kind * -> *. --gog (2007-01-18)


 * You are so right (and you have given me a better grasp what kinds are for). I got confused glancing down at the instance for State, but of course I forgot that the s in State s refers to the thing we're passing around.  Sorry about that.  -- Kowey 12:35, 18 January 2007 (UTC)

Shouldn't be

case b_v of  Nothing -> Nothing Just v -> f v

instead of

case b_v of  Nothing -> Nothing Just v -> Just $ f v ? --buben.razuma 14:27, 5 April 2007 (UTC)


 * I don't think so, because f v already is of type  -- Kowey 19:10, 5 April 2007 (UTC)


 * Yes, it is, that's what I mean. The second snippet is what's written and the first one is what should be. --buben.razuma 19:16, 5 April 2007 (UTC)


 * Eep! You're quite right... hmm... maybe worth taking a second look at that MaybeT... Sorry, I wasn't reading carefully enough. Thought you were talking about the other way around  -- Kowey 05:29, 6 April 2007 (UTC)

StateT definition
I don't see the point of the extra return and (<-) operator in the implementation of the bind operator of StateT: (StateT x) >>= f = StateT $ \s -> do -- get new value, state (v,s') <- x s -- apply bound function to get new state transformation fn (StateT x') <- return $ f v -- apply the state transformation fn to the new state x' s' Couldn't we use let instead?: (StateT x) >>= f = StateT $ \s -> do -- get new value, state (v,s') <- x s -- apply bound function to get new state transformation fn let (StateT x') = f v -- apply the state transformation fn to the new state x' s' -- Auders (talk) 20:28, 28 June 2008 (UTC)


 * Yes, the  is bad style here. Changed to   to mimic the use of  .-- apfe&lambda;mus 10:16, 29 June 2008 (UTC)

MonadPlus (MaybeT m)
I tried to copy classes and instances definitions for `MaybeT` into file and trying to run it with GHCi. But I am getting a bit cryptic error message: [1 of 1] Compiling Main            ( Main.hs, interpreted )

Main.hs:28:10: Could not deduce (GHC.Base.Alternative (MaybeT m)) arising from the superclasses of an instance declaration from the context (Monad m)     bound by the instance declaration at Main.hs:28:10-40 In the instance declaration for ‘MonadPlus (MaybeT m)’ Failed, modules loaded: none.

Here is my complete .hs-file: module Main where

import Control.Monad import Control.Monad.Trans.State import Control.Monad.Trans.Class import System.Random

newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) }

instance Monad m => Monad (MaybeT m) where return = MaybeT. return. Just

x >>= f = MaybeT $ do maybe_value <- runMaybeT x                         case maybe_value of                               Nothing    -> return Nothing Just value -> runMaybeT $ f value

instance Monad m => Functor (MaybeT m) where fmap = liftM

instance Monad m => Applicative (MaybeT m) where pure = return (<*>) = ap

instance Monad m => MonadPlus (MaybeT m) where mzero    = MaybeT $ return Nothing mplus x y = MaybeT $ do maybe_value <- runMaybeT x                           case maybe_value of                                 Nothing    -> runMaybeT y                                 Just _     -> return maybe_value

instance MonadTrans MaybeT where lift = MaybeT. (liftM Just)

My GHCi version is: $ ghci --version The Glorious Glasgow Haskell Compilation System, version 7.10.3

Am I missing something? 79.173.88.26 (discuss) 21:25, 5 January 2016 (UTC)


 * You are not doing anything wrong. The issue is that from GHC 7.10 onwards not only  is a superclass of   but also   (which is to   what   is to  ) is a superclass of  . That means the example code was only half-converted to 7.10 -- to make it work, we would also need to add the   instance, which is the really same one written for  :

instance Monad m => Alternative (MaybeT m) where empty    = MaybeT $ return Nothing x <|> y  = MaybeT $ do maybe_value <- runMaybeT x                            case maybe_value of                                 Nothing    -> runMaybeT y                                 Just _     -> return maybe_value

instance Monad m => MonadPlus (MaybeT m) where mzero = empty mplus = (<|>)


 * That wasn't fixed yet because doing so in the proper way requires rewriting the  chapter so that it also talks about    as well, which in principle calls for explaining   in at least a preliminary way amidst these monad chapters -- and figuring out the best way of rearranging the book to do that is still a bit of an open problem... --Duplode (discuss • contribs) 06:23, 6 October 2016 (UTC)

requests

 * 1) Could a motivating example be put near the beginning of this article, e.g. something that shows exactly why you would use a transformer and how you'd use it to combine actions from two different monads.
 * 2) The table of transformers in the "cousins" section should include a row for MaybeT since MaybeT is explained in detail further down.  MaybeT is probably a good candidate for the motivating example above as well, since Maybe is such a simple monad.  So you'd have an example of using MaybeT near the top, then go on to the implementation explanation further down.  Any other transformers mentioned in the article should also be put in the table, if they're not already there.
 * 3) I'm a bit fuzzy about this but "The type constructor Reader r is an instance of the Monad class" looks a little odd to me; I thought that types (not type constructors) were instances of type classes.  Am I missing something?  If there's a distinction, is it just a pedantic one?
 * Thanks.


 * Yes. The chapters about monads are currently undergoing a rewrite, starting with Haskell/Understanding monads. So, this chapter will be rewritten too and get motivation, but I can't say when :-)
 * Yes. Someone please do so.
 * Type constructors (i.e. things of kind ) can indeed be instances of classes two. In fact, this feature was added to Haskell exactly to make the monad class possible. So, the the constructor   is the monad, not the "concrete" type   (of kind  ). Haskell/Understanding monads already contains a bit of info on this.
 * -- apfe&lambda;mus 11:19, 5 August 2007 (UTC)


 * I'm not sure I want to be tinkering with the article text, but here's a motivating example I emailed a friend once. I think it's right. It may be of some use:


 * Concrete example: Suppose I was writing a server. Each client thread must be of type IO (that's because forkIO :: IO  -> IO ThreadID)).


 * Suppose also that this server has some configuration that (in an imperative program) would be global that the clients all need to query.


 * > data Config = Config Foo Bar Baz


 * One way of doing this is to use currying and making all the client threads of type Config -> IO . Not too nice because any functions they call have to be passed the Config parameter manually. The Reader monad solves this problem but we've already got one monad. We need to wrap IO in a ReaderT. The type constructor for ReaderT is ReaderT r m a, with r the shared environment to read from, m the inner monad and a the return type. Our client_func becomes:


 * > client_func :: ReaderT Config IO


 * We can then use the ask, asks and local functions as if Reader was the only Monad:


 * (these examples are inside do blocks)


 * > p <- asks port


 * (Assuming some function port :: Config -> Int or similar.)


 * To do stuff in IO (or in the general case any inner monad) the liftIO function is used to make an IO function work in this wrapped space:


 * (given h :: Handle, the client's handle)


 * > liftIO $ hPutStrLn h "You lose"
 * > liftIO $ hFlush h


 * IO is once again special. For other inner monads, the lift function does the same thing. Note also that IO has no transformer and must therefore always be the innermost monad.


 * This is all well and good, but the client_func now has type ReaderT Config IO and forkIO needs a function of type IO . The escape function for Reader is runReader :: Reader r a -> r -> a and similarly for ReaderT the escape function is runReaderT :: ReaderT r m a -> r -> m a:


 * (Given some c :: Config that's been assembled from config files or the like)


 * > forkIO (runReaderT client_func c)


 * Will do the trick.


 * Monad transformers are like onions. They make you cry but you learn to appreciate them. Like onions, they're also made of layers. Each layer is the functionality of a new monad, you lift monadic functions to get into the inner monads and you have transformerised functions to unwrap each layer. They're also like a present in that regard: in this example we unwrapped the outer wrapping paper to get to the present: an object of type IO, which let us make haskell do something. 129.11.251.78 (talk) 23:26, 13 December 2007 (UTC)

Dead links.
Please fix up the ghc documentation links. Thanks for the great tutorial.

2012-05-06 reorganization
I have just performed a major reorganization in the article. The getPassword example, which introduces transformers though MaybeT, was made slightly more detailed to work better as an introduction. The corresponding section about MaybeT further in the page was removed, along with most references to the sandwich analogy (though I left a body note about it near the beginning). The dissection of ListT was grouped at the end with the StateT discussion; the lift section now precedes it. The older introduction is mostly gone, with only the All About Monads derived part (the one with the table) remaining, and even that was completely reworked to fit the surrounding context (a later addition to it, which tried to generalize the non-generalizable was summarily removed). Hopefully you will find the text much more readable now. There are still improvements to be made - IMO, the key one is adding better practical exercises (I have a few ideas about that) and providing solutions to the existing ones. --Duplode (discuss • contribs) 13:22, 6 May 2012 (UTC)

2015-09-11 cleanup
A general cleanup of the sections after the  introduction was performed, with the main goal of clarifying some confusing passages and shifting the focus of some others. Solutions to the exercises were added as well. Remaining concerns include:


 * The  discussion was mercilessly removed, mostly to avoid facing the infamous "ListT done wrong" issue (that is, the fact that the   in transformers violates the monad laws when used with non-commutative base monads).
 * Calling the non-transformer "cousin" of a monad transformer "base monad" is unfortunate, as "base monad" usually refers to what this chapter calls "inner monad".
 * The password example should probably include a runnable full-program demonstration.

This is the latest revision before the cleanup.

Duplode (discuss • contribs) 10:17, 11 September 2015 (UTC)


 * The issue with "inner" vs "base" monad looks a bit confusing indeed. Intuitively, i felt that in,   is the base monad and   is the inner, because   is essentially   (with   inside), and i would say that   is based on  .  This also agrees with the usage in Control.Monad.Trans.Class documentation.  However, to be sure, i would have liked to know if there is any relevant mathematical terminology. --Alexey Muranov (discuss • contribs) 17:08, 21 April 2017 (UTC)


 * Indeed, that definitely needed fixing -- thanks for reminding me of it. The transformers documentation uses "base monad" and "inner monad" as synonyms (contrast the passages that talk about "an operation runXXXT to unwrap the transformer, exposing a computation of the inner monad" and "a mapping from transformations between base monads"), and doing anything else is likely to result in confusion. That being so, I changed the text so that "base monad" now refers to e.g.  in  . It is trickier to pick a term for the role of , and there isn't really an established choice. Since the monad in this role often isn't literally part of the unwrapped type, but only notionally so (an example of that is  ), explanations about transformers tend to talk about them in more abstract terms (such as "added effect", or "added feature"). Taking that into account, I provisionally changed it to "precursor monad", in the sense of a conceptual precursor to the transformer. I also thought of "model monad", which might capture the idea better, at the cost of appropriating a word with significantly more baggage. If you have other suggestions, I'm all ears! --Duplode (discuss • contribs) 08:26, 22 April 2017 (UTC)


 * How about imitating the OOP and calling  in   the base or parent monad?  As to , what about feature monad?
 * I tried to follow some links and references from the nLab page on Monad transformers, but didn't find so far any special terms for these notions. (I wonder if these notions are not too unimportant from the general theoretical viewpoint.)  I do not know much about this subject so far. --Alexey Muranov (discuss • contribs) 13:21, 22 April 2017 (UTC)


 * Yup, in the first case "base monad" is the way to go. As for the second case, "feature monad" might work too. In a similar vein, I had thought about "added monad", but that might be confusing in the cases in which the "added" monad isn't literally there. Another option worth considering is rewriting everything so that we don't refer to it as a monad, but rather as the "added feature" (or "added effect", etc.). That might make some passages less clumsy (in particular, the paragraph after the table in the "Type juggling" subsection).


 * As for math references, as far as I'm aware of your suspicion is right: this is a topic more interesting to Haskellers than to category theorists, and so the mathematical literature doesn't have much to say about terminology.


 * Duplode (discuss • contribs) 20:12, 22 April 2017 (UTC)

MonadState instance declaration
This is a bit confusing. The explanation in the box is especially confusing. Nowhere have we talked about a set of types that "together form an instance of" some type class. Does the  class have a parameter  ?


 * "Does the  class have a parameter  ?" Yes, it does; and no, we haven't talked about such things before. That is an example of a multi-parameter type class, one of the many type system extensions in common use. It is the sort of detail we would rather not emphasise during an introductory presentation of something else, and so the note was an attempt to not leave it unmentioned without bogging down the reader in details. The wording probably can be improved -- perhaps it glosses over the issue a little too much. --Duplode (discuss • contribs) 05:59, 6 October 2016 (UTC)

askPassphrase not exactly the same.
Great tutorial, but the simplified 'askPassphrase' function is not equivalent. There is no printing of "Passphrase invalid." in the transformer version.