Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correct usage of the do notation

Tags:

haskell

monads

I am trying to understand Monad and I have the following code

f a b c d =
   do one <- a + b
      two <- c * d
      three <- one + two
      return three

The above compiles

but get the an error when I

*Main> f 1 2 3 4

:1:1:
    No instances for (Num (a0 -> t0), Monad ((->) a0), Monad ((->) t0))
      arising from a use of `f'
    Possible fix:
      add instance declarations for
      (Num (a0 -> t0), Monad ((->) a0), Monad ((->) t0))
    In the expression: f 1 2 3 4
    In an equation for `it': it = f 1 2 3 4

:1:9:
    No instance for (Num (a0 -> a0 -> t0))
      arising from the literal `4'
    Possible fix:
      add an instance declaration for (Num (a0 -> a0 -> t0))
    In the fourth argument of `f', namely `4'
    In the expression: f 1 2 3 4
    In an equation for `it': it = f 1 2 3 4

I think I would be one step closer to understand Monad if I know why the above code dont work on
f 1 2 3 4

like image 838
nobody Avatar asked Nov 29 '22 15:11

nobody


2 Answers

The problem is you are confusing wrapped monadic values with pure values.

The first thing to know is that do notation is syntactic sugar for regular function calls (>>= and >>). So, it would help to see what your code desugars too.

Lets try something simpler

 f a b =
   do one <- a + b
      return one

This has the same problem as your code, but is simpler. To understand why it doesn't work we ask: what does this actually mean? Well, we can rewrite the <- symbol using >>=

 f a b = (a + b) >>= \x -> return x

(this is not the simplest representation, but makes the point clear)

If you test the following in GHCi

 >> :t (>>=)
 Monad m => m a -> (a -> m b) -> m b

that is, the function >>= takes: an argument of type m of a and a function from a to m of b and returns a m of b.

What about in this code?

(a + b)

Is going to be a number. How about the other half

 \x -> return x

Takes an object of type a and returns an object of type m a for any a

So, you need to have a number, that is also some sort of monad of something. Can you think of anything like that? It is not clear what this would be, which is a reason to be suspicious that this should type check.

One good way to come to terms with monads is to look at some specific examples.

The Maybe monad expresses computations that might fail

 instance Monad Maybe where
      return = Just
      (>>=) (Just a) f = f a
      (>>=) Nothing _ = Nothing

This lets you say things with a patter like

 f args = do x <- functionThatMightFail args
             y <- anotherfunctionThatMightFail x
             return y

or the same code more simply

f args = do x <- functionThatMightFail args
            anotherfunctionThatMightFail x

or perhaps

f args = functionThatMightFail args >>= anotherfunctionThatMightFail

On the other hand the List monad captures the idea of performing the same function on every element of a list, and then concatenating the results together. Simple examples abound:

f = do x <- [1,2,3,4]
       [1..x]

If you understand these ones, play with the State monad. It helps you get the more general idea that "monads are models of computation." I would then checkout Parsec, and of course, IO

like image 169
Philip JF Avatar answered Dec 02 '22 04:12

Philip JF


I'm going to disagree with everyone else and say what you're doing almost certainly simply isn't related to monads. You probably just want to use some boring old code like this instead:

f a b c d = three where
    one = a + b
    two = c * d
    three = one + two

or more succinctly:

f a b c d = a + b + c * d
like image 44
Daniel Wagner Avatar answered Dec 02 '22 05:12

Daniel Wagner