简体   繁体   中英

Understanding monadic function composition

I am learning about monads from the book 'Learn You a Haskell for Great Good!' by Miran Lipovaca. I am trying to understand the associativity law for monads. Essentially, the law states that when you have a chain of monadic function applications with >>= , it shouldn't matter how they're nested.

The following code enables one to pass the result of a function of type a -> mb to a function of type b -> mc :

(<=<) :: (Monad m) => (b -> m c) -> (a -> m b) -> (a -> m c)
f <=< g = (\x -> g x >>= f)

However, for the example below:

ghci> let f x = [x, -x]
ghci> let g x = [x*3, x*2]
ghci> let h = f <=< g
ghci> h 3
[9, -9, 6, -6]

Are fx and gx both functions? It seems to be that they are lists with different values of x and not functions. How does the line let h = f <=< g work in the above code? f and g have to be functions since they are used with <=< but I am not sure what they are.

f x = [x, -x]

This is ordinary function definition syntax. We are defining a new function f , by writing down what it would produce when applied to a hypothetical value x .

let (whether as a statement or a let ... in ... expression) just introduces a block where you can make definitions, much like where . The definitions themselves use the same syntax as global ones do.

If you know how to define functions by writing eg plusOne n = n + 1 in a file, then this syntax is exactly the same (if you don't know how to do that, then I'd suggest reading through some introductory tutorials on fundamental Haskell syntax before you try to understand monadic function composition).

So after those definitions f and g are functions. fx and gx don't really make sense, since you don't have an x in scope to apply them to.

If you did have such a value in scope, then fx would be an expression that evaluates to a list, which involves calling the function f . It still wouldn't be true to say that fx or gx are functions.

So now it should be clear that let h = f <=< g is defining a new value h by applying the <=< operator to f and g .

Nothing's better for gaining a feeling of understanding, like working through the definitions by hand on a sheet of paper.

fx = [x, -x] can also be written f = (\\ x -> [x, -x]) . Thus

  h 3 
= {- by def of h -}
  (f <=< g) 3 
= {- by def of (<=<) -}
  (\x -> g                   x >>= f               ) 3
= {- by defs of f and g -}
  (\x -> (\ x -> [x*3, x*2]) x >>= (\ x -> [x, -x])) 3
= {- by substitution -}
         (\ x -> [x*3, x*2]) 3 >>= (\ x -> [x, -x])
= {- by substitution -}
                 [3*3, 
                  3*2]         >>= (\ x -> [x, -x])
= {- by definition of (>>=) for [] -}
  concat [       (3*3)         &   (\ x -> [x, -x])  -- x & f == f x
         ,       (3*2)         &   (\ x -> [x, -x]) 
         ]
= {- by definition of concat -}
                 (3*3)         &   (\ x -> [x, -x])
         ++      (3*2)         &   (\ x -> [x, -x]) 
= 
  [9, -9, 6, -6]

( edit ) For a picture, and some more discussion of these Kleisli arrows and their composability, see this older answer of mine .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM