Monad laws
From HaskellWiki
(eliminate references to law #N) |
(possible half-way point?) |
||
(3 intermediate revisions by 2 users not shown) | |||
Line 14: | Line 14: | ||
|- |
|- |
||
| '''Associativity:''' |
| '''Associativity:''' |
||
− | | <haskell>(m >>= (\x -> f x)) >>= g</haskell> |
+ | | <haskell>(m >>= f) >>= g</haskell> |
| ≡ |
| ≡ |
||
| <haskell>m >>= (\x -> f x >>= g)</haskell> |
| <haskell>m >>= (\x -> f x >>= g)</haskell> |
||
Line 29: | Line 29: | ||
| '''Left identity:''' |
| '''Left identity:''' |
||
| <haskell> |
| <haskell> |
||
− | do |
+ | do { x' <- return x; |
− | x' <- return x |
+ | f x' |
− | f x' |
+ | } |
</haskell> |
</haskell> |
||
| ≡ |
| ≡ |
||
| <haskell> |
| <haskell> |
||
− | do |
+ | do { f x } |
− | f x |
||
</haskell> |
</haskell> |
||
|- |
|- |
||
| '''Right identity:''' |
| '''Right identity:''' |
||
| <haskell> |
| <haskell> |
||
− | do |
+ | do { x <- m; |
− | x <- m |
+ | return x |
− | return x |
+ | } |
</haskell> |
</haskell> |
||
| ≡ |
| ≡ |
||
| <haskell> |
| <haskell> |
||
− | do |
+ | do { m } |
− | m |
||
</haskell> |
</haskell> |
||
|- |
|- |
||
| '''Associativity:''' |
| '''Associativity:''' |
||
| <haskell> |
| <haskell> |
||
− | do |
+ | do { y <- do { x <- m; |
− | y <- do |
+ | f x |
− | x <- m |
+ | } |
− | f x |
+ | g y |
− | g y |
+ | } |
</haskell> |
</haskell> |
||
| ≡ |
| ≡ |
||
| <haskell> |
| <haskell> |
||
− | do |
+ | do { x <- m; |
− | x <- m |
+ | do { y <- f x; |
− | do |
+ | g y |
− | y <- f x |
+ | } |
− | g y |
+ | } |
</haskell> |
</haskell> |
||
| ≡ |
| ≡ |
||
| <haskell> |
| <haskell> |
||
− | do |
+ | do { x <- m; |
− | x <- m |
+ | y <- f x; |
− | y <- f x |
+ | g y |
− | g y |
+ | } |
</haskell> |
</haskell> |
||
|} |
|} |
||
Line 85: | Line 85: | ||
<haskell> |
<haskell> |
||
skip_and_get = do |
skip_and_get = do |
||
− | unused <- getLine |
+ | unused <- getLine |
− | line <- getLine |
+ | line <- getLine |
− | return line |
+ | return line |
</haskell> |
</haskell> |
||
Line 95: | Line 95: | ||
<haskell> |
<haskell> |
||
skip_and_get = do |
skip_and_get = do |
||
− | unused <- getLine |
+ | unused <- getLine |
− | getLine |
+ | getLine |
</haskell> |
</haskell> |
||
Line 103: | Line 103: | ||
<haskell> |
<haskell> |
||
main = do |
main = do |
||
− | answer <- skip_and_get |
+ | answer <- skip_and_get |
− | putStrLn answer |
+ | putStrLn answer |
</haskell> |
</haskell> |
||
Line 112: | Line 112: | ||
<haskell> |
<haskell> |
||
main = do |
main = do |
||
− | answer <- do |
+ | answer <- do |
− | unused <- getLine |
+ | unused <- getLine |
− | getLine |
+ | getLine |
− | putStrLn answer |
+ | putStrLn answer |
</haskell> |
</haskell> |
||
Line 122: | Line 122: | ||
<haskell> |
<haskell> |
||
main = do |
main = do |
||
− | unused <- getLine |
+ | unused <- getLine |
− | answer <- getLine |
+ | answer <- getLine |
− | putStrLn answer |
+ | putStrLn answer |
</haskell> |
</haskell> |
||
Line 144: | Line 144: | ||
(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c |
(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c |
||
(m >=> n) x = do |
(m >=> n) x = do |
||
− | y <- m x |
+ | y <- m x |
− | n y |
+ | n y |
</haskell> |
</haskell> |
||
Latest revision as of 18:00, 5 April 2012
All instances of the Monad typeclass should obey the three monad laws:
Left identity: | return a >>= f |
≡ | f a |
Right identity: | m >>= return |
≡ | m |
Associativity: | (m >>= f) >>= g |
≡ | m >>= (\x -> f x >>= g) |
Here, p ≡ q simply means that you can replace p with q and vice-versa, and the behaviour of your program will not change: p and q are equivalent.
[edit] 1 What is the practical meaning of the monad laws?
Let us re-write the laws in do-notation:
Left identity: | do { x' <- return x; f x' } |
≡ | do { f x } | ||
Right identity: | do { x <- m; return x } |
≡ | do { m } | ||
Associativity: | do { y <- do { x <- m; f x } g y } |
≡ | do { x <- m; do { y <- f x; g y } } |
≡ | do { x <- m; y <- f x; g y } |
In this notation the laws appear as plain common-sense transformations of imperative programs.
[edit] 2 But why should monads obey these laws?
When we see a program written in a form on the left-hand side, we expect it to do the same thing as the corresponding right-hand side; and vice versa. And in practice, people do write like the lengthier left-hand side once in a while. First example: beginners tend to write
skip_and_get = do unused <- getLine line <- getLine return line
and it would really throw off both beginners and veterans if that did not act like (by right identity)
skip_and_get = do unused <- getLine getLine
Second example: Next, you go ahead to use skip_and_get:
main = do answer <- skip_and_get putStrLn answer
The most popular way of comprehending this program is by inlining (whether the compiler does or not is an orthogonal issue):
main = do answer <- do unused <- getLine getLine putStrLn answer
and applying associativity so you can pretend it is
main = do unused <- getLine answer <- getLine putStrLn answer
The associativity law is amazingly pervasive: you have always assumed it, and you have never noticed it.
Whether compilers exploit the laws or not, you still want the laws for your own sake, just so you can avoid pulling your hair for counter-intuitive program behaviour that brittlely depends on how many redundant "return"s you insert or how you nest your do-blocks.
[edit] 3 But it doesn't look exactly like an "associative law"...
Not in this form, no. To see precisely why they're called "identity laws" and an "associative law", you have to change your notation slightly.
The monad composition operator (also known as the Kleisli composition operator) is defined in Control.Monad:
(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c (m >=> n) x = do y <- m x n y
Using this operator, the three laws can be expressed like this:
Left identity: | return >=> g |
≡ | g |
Right identity: | f >=> return |
≡ | f |
Associativity: | (f >=> g) >=> h |
≡ | f >=> (g >=> h) |
It's now easy to see that monad composition is an associative operator with left and right identities.
This is a very important way to express the three monad laws, because they are precisely the laws that are required for monads to form a mathematical category. So the monad laws can be summarised in convenient Haiku form:
- Monad axioms:
- Kleisli composition forms
- a category.