The best introduction to monads was written in 2006 (more than eight years ago now) and I don't imagine that a better one will be written in the near future -
http://blog.sigfpe.com/2006/08/you-could-have-invented-monad...
The best introduction to monads was written in 2006 (more than eight years ago now) and I don't imagine that a better one will be written in the near future -
http://blog.sigfpe.com/2006/08/you-could-have-invented-monad...
The simplest way to encapsulate data is to wrap it using a constructor which we keep private to our module:
module M1 (Encap(), val1, val2)
data Encap a = mkEncap a
val1 :: Encap Int
val1 = mkEncap 5
val2 :: Encap Int
val2 = mkEncap 10
Other modules importing M1 get access to the Encap type, val1 and val2 but not the mkEncap constructor. They can use val1 and val2 as-is, but they can't construct new Encap values or destruct existing Encap values to get at their contents. The problem is, there's not much we can do with this interface.One way we can make this more useful is being able to apply some function to an encapsulated value. That's what Functor is for, so we can add this to M1:
instance Functor Encap where
fmap f (mkEncap x) = mkEncap (f x)
Now users of M1 can transform encapsulated values without being able to break the encapsulation. For example: val1Plus7 :: Encap Int
val1Plus7 = fmap (+7) val1
val2Str :: Encap String
val2Str = fmap show val2
We're still pretty limited though, since there's no way to combine encapsulated values into new encapsulated values, or to encapsulate our own values. That's what Applicative provides, by letting us construct encapsulated values without gaining the ability to destruct them, and by allowing encapsulated functions to be applied to encapsulated values (since functions are closures, this lets us gather up encapsulated values and combine them arbitrarily): instance Applicative Encap where
pure x = mkEncap x
(mkEncap f) <*> (mkEncap x) = mkEncap (f x)
Now users of M1 can encapsulate and combine values, like this: -- val1 + val2
val1PlusVal2 :: Encap Int
val1PlusVal2 = fmap (+) val1 <*> val2
-- New encapsulated string
val3 :: Encap String
val3 = pure "Hello world"
-- val3 repeated val1 times
val3Repeated :: Encap String
val3Repeated = fmap rep val1 <*> val3
where rep n _ | n <= 0 = ""
rep n s = s ++ rep (n-1) s
This is quite a powerful interface, but one thing we can't do is `collapse` double-encapsulated values into single-encapsulated values. That's what Monad provides: join :: Encap (Encap a) -> Encap a
join (mkEncap (mkEncap x)) = mkEncap x
An alternative, but equivalent, definition is to allow calls to encapsulation-producing functions without encapsulating their result. Haskell's Monad is defined this way: instance Monad Encap where
(>>=) :: Encap a -> (a -> Encap b) -> Encap b
(mkEncap x) >>= f = f x
These kind of encapsulated values turns out to hold effects without breaking the language, and these interfaces turn out to be powerful enough for general computation.Thanks Chris!
I wonder if you're hand-waving a bit here. To me "encapsulated values" describes Identity or Maybe, but really doesn't work (IMO) for e.g. State or IO where bind is composition.
Maybe my terminology could have been better, but I meant "encapsulated" in analogy to OOP, which advocates "encapsulating" all data via methods. The OOP definition of encapsulation includes using getters/setters, which is like having "wrapped-up" properties, but the idea is that we can go beyond this to calculate the data in arbitrary ways without our clients having to know about the implementation. That's what I was trying to get at here; for example, the implementation of IO involves horrible imperative yukiness, but we (the client) don't need to know that: we just use the interface, and if our functions ever get called, they will be given an appropriate argument.
The example:
return 7 >>= (\x -> Writer (x+1,"inc."))
>>= (\x -> Writer (2*x,"double."))
>>= (\x -> Writer (x-1,"dec."))
works for this example, but a more accurate representation of how "do" notation is expanded is: return 7 >>= (\x -> Writer (x+1,"inc.")
>>= (\x -> Writer (2*x,"double.")
>>= (\x -> Writer (x-1,"dec."))))
Note that I've moved the parentheses.Actually, you can, equivalently, omit the parentheses for the same meaning, because the '->' has very low precedence:
return 7 >>= \x -> Writer (x+1,"inc.")
>>= \x -> Writer (2*x,"double.")
>>= \x -> Writer (x-1,"dec.")
The point is, most times each of subsequent functions need to "see" what was in scope in the earlier functions. Most times, the later monadic actions need information that is pulled out of the monad in previous actions.For example, consider the following:
main = putStrLn "Enter your first name" >>=
\_ -> getLine >>=
\first -> putStrLn "Enter your last name" >>=
\_ -> getLine >>=
\last -> putStrLn ("Hello " ++ first ++ " " ++ last ++ ".")
The last monadic action needs both "first" and "last" to both be in scope. This only works because of the way that it is implicitly parenthesized.Until I "got" this, I was very confused by most of the Monad examples I found.
Here's an article I wrote about the IO monad which also makes this point: https://github.com/Patient0/IOMonad
It is perfectly reasonable to also read this as the list of elements of monadery that even tutorials written in Haskell tend to miss or fail to explain.
> Monads are not "about effects".
What is your definition of "effects"? I ask because this article[0] and many others[1] seem[2] to use a contradictory definition, in which failure, nondeterminism, state etc. are viewed as effects and monads are a means of implementing those effects.
------
[0]: http://www.sciencedirect.com/science/article/pii/S2352220814...
[1]: http://scholar.google.com/scholar?q=algebraic+effects+monad&...
[2]: as far as I understand them; I may be wrong.
So to summarize: effects are a general concept, monads are a particular technology for implementing that concept.
Further complexity ensues when people start talking about the general concept of a monad which is interesting in its own right but it has a more sophisticated relationship with the concept of effects.
[0] Purity is a property of, say, functions. Its definition is a function `f` is pure if and only if
const () . f = const ()
which usually means that non-termination is impure as well. The notion of equality you use above can finesse this definition a lot.[1] As stated in [0], non-termination is an effect, so Haskell monads are impure in that sense. Haskell typically ignores non-termination effects, though. Generally, monads would work more or less just fine even without non-termination though. Externally you can think of them as pure.
In addition to tel's discussion, what I was really trying to get at is that monads aren't "about" IO effects in particular, they're not about "impurity". In this case the whole thing is pure.
Defining effects at a deep programming language research level can bring a different understanding, where all monads are about effects, but "effects" has a different meaning that most people understand.
I'll ponder how to clarify that better.
... but I may be wrong about that.
http://ericlippert.com/2013/02/21/monads-part-one/
A lot of Monad articles like to explain 'what' without first establishing 'why' (IMHO)