Haskell——Monadic-Programming-in-Haskell
All About Monads
A monad is more of a design pattern than a data structure. That is, there are many data structures that, if you look at them in the right way, turn out to be monads.
The name "monad" comes from the mathematical field of category theory, which studies abstractions of mathematical structures. If you ever take a PhD level class on programming language theory, you will likely encounter that idea in more detail. Here, though, we will omit most of the mathematical theory and concentrate on code.
Follow the tutorial aiming to explain the concept of a monad ant its application to functional programming in a way that is easy to understand and useful to beginning and intermediate Haskell programmers.
Well I need to be a little familiar with Haskell language.
The tutorial is arrange in three parts:
Part 1: Understanding Monads
This part provide a basic understanding of the role of monads in functional programming, how monads operate, and how they are declared and used in Haskell.
Part 2: A Catalog of Sttandard Monads
This part covers each standard monad in Haskell, giving the definition of the monad and discussing the use of the monad.
Part 3: Monads in the Real World
This part covers advanced material relating to monad transformers and real-world issues encountered when programming with monads.
THE BEST WAY TO REALLY UNDERSTAND MONADS IS TO EXPERIMENT WITH MONADIC CODE!
Part 1: Understanding Monads
What is a monad
In short: It is useful to think of a monad as a strategy for combining computations into more complex computations.
Consider a layer of indirection(abstract) at the computations domain and functional programming.
Why should I make the effort to understand monads
According to the author, it is a promising way to help improve code and extend capabilities.
Three useful properties
Modularity
They allow computations to be composed from simpler computations and separate the combination strategy from the actualcomputations being performed.
Flexibility
They allow functional programs to be much more adaptable than equivalent programs written without monads. This is becausethe monad distills the computational strategy into a single place instead of requiring it be distributed throughout the entire program.
Isolation
They can be used to create imperative-style computational structures which remain safely isolated from the main body of thefunctional program. This is useful for incorporating side-effects (such as I/O) and state (which violates referential transparency) into a purefunctional language like Haskell.
Meet the Monads
Type constructors
Use Maybe type constructor throughout this chapter. Maybe in Haskell is similar to option in OCaml. Take the code in [Real World Ocaml] as an example:
1 | |
The toplevel will show
1 | |
In Haskell, the definition of Maybe is:
1 | |
Noticing the polymorphic a, Maybe Int can be thought of as a Maybe container holding an Int value (or Nothing) and Maybe String would be a container holding a String value (or Nothing same to above).
Maybe a monad
In Haskell a monad is represented as
- a type constructor (call it
m) - a function that builds value of that type (
a -> m a) - and a function that combines values of that type with computations that produce values of that type to produce a new computation for values of that type (
m a -> (a -> m b) -> m b) (is know as "bind")
The signatures of the functions are (in Haskell and OCaml):
1 | |
1 | |
As for the example of caculate the genetic history in sheep cloning experiments.
Bad programming style
1 | |
It get even worse if we want to find great grandparents:
1 | |
Let Maybe a monad!
We consider Maybe as the type of monad m, and it's clear that the return function are Jusa a or Nothing. It is clear that a Nothing value at any point in the computation will cause Nothing to be final result. So good programming style would have us create a combinator that captures the behavior we want:
1 | |
Though we give the comb signatures as Maybe a -> (a -> Maybe b) -> Maybe b which means a b could be different types, we applied comb with mother and father which implies a and b are actually the same(Sheep). Just as the tutorial says:
The combinator is a huge success! The code is much cleaner and easier to write, understand and modify. Notice also that the
combfunction isentirely polymorphic --- it is not specialized forSheepin any way. In fact, the combinator captures a general strategy for combining computations that may fail to return a value. Thus, we can apply the same combinator to other computations that may fail to return a value, suchas database queries or dictionary lookups.
Return
In terms of computations, return is intended to have some kind of trivial effect. For example, if the monad represents computations whose side effect is printing to the screen, the trivial effect would be to not print anything.
Bind
- a boxed value, which has type
'a t(OCaml), and - a function that itself takes un unboxed value of type
'aas input and returns a boxed value of type'b tas output.
In terms of computations, bind is intended to sequence effects one after another. Continuing the running example of printing, sequencing would mean first printing one string, then another, and bind would be making sure that the printing happens in the correct order.
Doing it with class
Learning Haskell type classes
Not necessary but is recommended.
The standard Monad class definition isn Haskell looks something like this.
1 | |
while in Coq
1 | |
Example continued
1 | |
Fit into Monad framework as an instance of Monad class.
The monad laws
Monadic operations must obey a set of laws, known as "the monad axioms".
The three fundamental laws
To be a proper monad, the return and >>= functions must work together according to three laws.
(return x) >>= f == f xm >>= return == m(m >>= f) >>= g == m >>= (\x -> f x >>= g)
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!