Search code examples
haskellmonads

Control.Monad.Writer example


Looking at some Writer monad examples, in the one from Learn You a Haskell I don't see where the use of * multiplication operator in the last line expression is overloaded to work with the with the Writer objects produced by the logNumber functions:

import Control.Monad.Writer  

logNumber :: Int -> Writer [String] Int  
logNumber x = Writer (x, ["Got number: " ++ show x])  

multWithLog :: Writer [String] Int  
multWithLog = do  
    a <- logNumber 3  
    b <- logNumber 5  
    return (a*b)

Solution

  • There seems to be some misunderstanding here. In your example code:

    import Control.Monad.Writer  
    
    logNumber :: Int -> Writer [String] Int  
    logNumber x = Writer (x, ["Got number: " ++ show x])  
    
    multWithLog :: Writer [String] Int  
    multWithLog = do  
        a <- logNumber 3  
        b <- logNumber 5  
        return (a*b)
    

    the values a and b are not Writer values. Their type is simply Int, and of course you can multiply 2 Ints. Therefore a*b is an Int too - note the use of return on it in the last line, which is needed here precisely in order to "lift" the "ordinary value" a*b of type Int to a "monadic value" of type Writer [String] Int.

    logNumber 3 is certainly a monadic value (of type Writer [String] Int), but the <- syntactic sugar of do notation "extracts" the underlying value out of it, and gives it a name - here a. More precisely, the do block above desugars to:

    multWithLog = logNumber 3 >>= \a -> logNumber 5 >>= \b -> return (a*b)
    

    where the lambda expressions have type Int -> Writer [String] Int (the arguments a and b being the Ints in question), which due to the type of >>= produces an expression of type Writer [String] Int overall.