Search code examples
haskellbindmonads

Bind operator for non-monadic functions


I more or less wrapped my head around monads, but i can't deduct how expression

(>>=) id (+) 3

evaluates to 6. It just seems the expression somehow got simplified to

(+) 3 3

but how? How is 3 applied twice? Could someone explain what is happening behind the scenes ?


Solution

  • This follows from how >>= is defined for the ((->) r) types:

    (f =<< g) x  =  f (g x) x
    

    Thus

    (>>=) id (+) 3
    =
    (id >>= (+)) 3
    =
    ((+) =<< id) 3
    =
    (+) (id 3) 3
    =
    3 + 3
    

    see the types:

    > :t let (f =<< g) x = f (g x) x in (=<<)
    let (f =<< g) x = f (g x) x in (=<<)
            :: (t1 -> (t2 -> t)) -> (t2 -> t1) -> (t2 -> t)
    
    > :t (=<<)
    (=<<) :: Monad m => (a -> m b) -> m a -> m b
    

    The types match with

    t1 ~ a
    (t2 ->) ~ m    -- this is actually ((->) t2)`
    t ~ b
    

    Thus the constraint Monad m here means Monad ((->) t2), and that defines the definition of =<< and >>= which get used.

    If you want to deduce the definition from the type,

    (>>=) :: Monad m => m a -> (a -> m b) -> m b
    m ~ ((->) r)
    
    (>>=) :: (r -> a) -> (a -> r -> b) -> (r -> b)
    (>>=)    f            g                r =  b
      where
      a  = f r
      rb = g a
      b  = rb r
    

    which after the simplification becomes the one we used above.

    And if you want to understand it "with words",

    (=<<) :: (Monad m, m ~ ((->) r)) => (a -> m b) -> m a -> m b
    (f =<< g) x  =  f (g x) x
    
    • g is a "monadic value" that "can compute" an "a", represented as r -> a
    • f a calculates a "monadic value" that "can compute" a "b", represented as r -> b,
    • thus \x -> f (g x) x is a monadic value that "can compute" a "b", given an "r".

    So these "non-monadic functions" are, in fact, monadic values, which happen to be functions.

    Thus in your example, g = id, f = (+), and

    • id is a "monadic value" that "can compute" an "a", an a -> a
    • (+) a calculates a "monadic value" that "can compute" a "b", an a -> b, which b is actually also an a,
    • thus \x -> (+) (id x) x is a monadic value that "can compute" an "a", given an "a":
    (>>=) id (+)
    =
    ((+) =<< id) 
    =
    \x -> (+) (id x) x
    =
    \x -> (+)     x  x