[Move the Maybe monad around. Bryan O'Sullivan **20071221055909] { hunk ./en/ch14-monads.xml 588 + + Putting a few misconceptions to rest + + We've now seen enough examples of monads in action to have + some feel for what's going on. Before we continue, there are a + few oft-repeated myths about monads that we're going to address. + You're bound to encounter these assertions in the + wild, so you might as well be prepared with a few good + retorts. + + + + Monads are hard to understand. + We've already shown that monads fall out + naturally from several problems. We've found that + the best key to understanding them is to explain several + concrete examples, then talk about what they have in + common. + + + + Monads are only useful for I/O and imperative + coding. While we use monads for I/O in Haskell, + they're valuable for many other purposes besides. We've + already used them for short-circuiting a chain of + computations, hiding complicated state, and logging. Even + so, we've barely scratched the surface. + + + + Monads are unique to Haskell. + Haskell is probably the language that makes the most + explicit use of monads, but people write them in other + languages, too, ranging from C++ to OCaml. + + + + Monads are for controlling the order of + evaluation. + + + + + + Building the Logger monad + + The definition of our Logger type is very + simple. + + &Logger.hs:Logger; + + It's a two-tuple, where the first element is the result of + an action, and the second is a list of messages logged while + that action was run. + + We've wrapped the tuple in a &newtype; to make it a distinct + type. The runLogger function extracts the + tuple from its wrapper. The function that we're exporting to + execute a logged action, execLogger, is + just a synonym for runLogger. + + &Logger.hs:execLogger; + + Our record helper function creates a + singleton list of the message we pass it. The result of this + action is (), so that's the value we put in the + result slot. + + Let's begin our Monad instance with &return;, + which is trivial: it logs nothing, and stores its input in the + return slot of the tuple. + + &Logger.hs:return; + + Slightly more interesting is &bind;, which is the heart of + the monad. It combines an action and a monadic function to give + a new result and a new log. + + &Logger.hs:bind; + + Let's spell out explicitly what is going on. We use + runLogger to extract the result + a from the action m, and + we pass it to the monadic function k. We + extract the result b from that in turn, and + put it into the result slot of the final action. We concatenate + the logs w and x to give + the new log. + + + Sequential logging, not sequential evaluation + + Our definition of &bind; ensures that messages logged on + the left will appear in the new log before those on the right. + However, it says nothing about when the values + a and b are evaluated: + &bind; is lazy. + + Like most other aspects of a monad's behaviour, strictness + is under the control of the monad's implementor. It's not a + constant that's shared by all monads. Indeed, some monads + come in multiple flavours, each with different levels of + strictness. + + + hunk ./en/ch14-monads.xml 801 - - - - Putting a few misconceptions to rest - - We've now seen enough examples of monads in action to have - some feel for what's going on. Before we continue, there are a - few oft-repeated myths about monads that we're going to address. - You're bound to encounter these assertions in the - wild, so you might as well be prepared with a few good - retorts. - - - - Monads are hard to understand. - We've already shown that monads fall out - naturally from several problems. We've found that - the best key to understanding them is to explain several - concrete examples, then talk about what they have in - common. - - - - Monads are only useful for I/O and imperative - coding. While we use monads for I/O in Haskell, - they're valuable for many other purposes besides. We've - already used them for short-circuiting a chain of - computations, hiding complicated state, and logging. Even - so, we've barely scratched the surface. - - - - Monads are unique to Haskell. - Haskell is probably the language that makes the most - explicit use of monads, but people write them in other - languages, too, ranging from C++ to OCaml. - - - - Monads are for controlling the order of - evaluation. - - - - - - Building the Logger monad - - The definition of our Logger type is very - simple. - - &Logger.hs:Logger; - - It's a two-tuple, where the first element is the result of - an action, and the second is a list of messages logged while - that action was run. - - We've wrapped the tuple in a &newtype; to make it a distinct - type. The runLogger function extracts the - tuple from its wrapper. The function that we're exporting to - execute a logged action, execLogger, is - just a synonym for runLogger. - - &Logger.hs:execLogger; - - Our record helper function creates a - singleton list of the message we pass it. The result of this - action is (), so that's the value we put in the - result slot. - - Let's begin our Monad instance with &return;, - which is trivial: it logs nothing, and stores its input in the - return slot of the tuple. - - &Logger.hs:return; - - Slightly more interesting is &bind;, which is the heart of - the monad. It combines an action and a monadic function to give - a new result and a new log. - - &Logger.hs:bind; - - Let's spell out explicitly what is going on. We use - runLogger to extract the result - a from the action m, and - we pass it to the monadic function k. We - extract the result b from that in turn, and - put it into the result slot of the final action. We concatenate - the logs w and x to give - the new log. - - - Sequential logging, not sequential evaluation - - Our definition of &bind; ensures that messages logged on - the left will appear in the new log before those on the right. - However, it says nothing about when the values - a and b are evaluated: - &bind; is lazy. - - Like most other aspects of a monad's behaviour, strictness - is under the control of the monad's implementor. It's not a - constant that's shared by all monads. Indeed, some monads - come in multiple flavours, each with different levels of - strictness. - }