53

Every time someone promises to "explain monads", my interest is piqued, only to be replaced by frustration when the alleged "explanation" is a long list of examples terminated by some off-hand remark that the "mathematical theory" behind the "esoteric ideas" is "too complicated to explain at this point".

Now I'm asking for the opposite. I have a solid grasp on category theory and I'm not afraid of diagram chasing, Yoneda's lemma or derived functors (and indeed on monads and adjunctions in the categorical sense).

Could someone give me a clear and concise definition of what a monad is in functional programming? The fewer examples the better: sometimes one clear concept says more than a hundred timid examples. Haskell would do nicely as a language for demonstration though I'm not picky.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • 2
    Perhaps this? http://en.wikipedia.org/wiki/Monad_%28category_theory%29#Formal_definition – kennytm Nov 22 '11 at 03:37
  • I know nothing of category theory, but this may be useful: http://books.google.com.au/books?id=MXboNPdTv7QC&pg=PA138&lpg=PA138&dq=%22monoid+in+the+category+of+endofunctors%22+mac+lane&source=bl&ots=feQWTkH2Uw&sig=tv-1JwaMOygKGmFE2vM2FhJVS9o&hl=en&ei=5iWsTJCkBIPSsAPQwJ36Aw&sa=X&oi=book_result&ct=result&redir_esc=y#v=onepage&q&f=false – Hugh Nov 22 '11 at 03:38
  • 6
    A monad in Haskell is a monad in the category of Haskell types and functions (parroting what someone told me in the #haskell IRC channel). The introduction of http://www.haskell.org/haskellwiki/Category_theory is insightful. – Joey Adams Nov 22 '11 at 03:43
  • @KennyTM: Thanks, but I'm pretty happy with the maths. I want to understand what monads are in functional programming. Maybe I should edit the title. – Kerrek SB Nov 22 '11 at 03:43
  • @Huw: I know the book -- it's OK, somewhat of a classic, but it doesn't concern functional programming :-) My question might be rephrased as "Explain it to me, trusting that I'll be able to follow you." – Kerrek SB Nov 22 '11 at 03:45
  • @JoeyAdams: Thank you, that looks promising! Please do feel free to flesh this out into an answer if you like :-) – Kerrek SB Nov 22 '11 at 03:50
  • 5
    Shameless self-plug: perhaps you would enjoy my [Zero Analogy Monad Tutorial](http://unknownparallel.org/monads.php) – Dan Burton Nov 22 '11 at 04:16
  • Thank you everyone, I'm appreciating lots of really great contributions! – Kerrek SB Nov 22 '11 at 14:25
  • Downvoter, care to explain your objection? – Kerrek SB Dec 15 '13 at 23:49
  • @DanBurton Your link is dead – Hjulle Aug 28 '15 at 12:46
  • 1
    @Hjulle The content just moved: https://unknownparallel.wordpress.com/zero-analogy-monad-tutorial/ – toraritte Jul 18 '17 at 18:36

8 Answers8

32

This question has some good answers: Monads as adjunctions

More to the point, Derek Elkins' "Calculating Monads with Category Theory" article in TMR #13 should have the sort of constructions you're looking for: http://www.haskell.org/wikiupload/8/85/TMR-Issue13.pdf

Finally, and perhaps this is really the closest to what you're looking for, you can go straight to the source and look at Moggi's seminal papers on the topic from 1988-91: http://www.disi.unige.it/person/MoggiE/publications.html

See in particular "Notions of computation and monads".


My own I'm sure too condensed/imprecise take:

Begin with a category Hask whose objects are Haskell types, and whose morphisms are functions. Functions are also objects in Hask, as are products. So Hask is Cartesian closed. Now introduce an arrow mapping every object in Hask to MHask which is a subset of the objects in Hask. Unit! Next introduce an arrow mapping every arrow on Hask to an arrow on MHask. This gives us map, and makes MHask a covariant endofunctor. Now introduce an arrow mapping every object in MHask which is generated from an object in MHask (via unit) to the object in MHask which generates it. Join! And from the that, MHask is a monad (and a monoidal endofunctor to be more precise).

I'm sure there is a reason why the above is deficient, which is why I'd really direct you, if you're looking for formalism, to the Moggi papers in particular.

Community
  • 1
  • 1
sclv
  • 38,665
  • 7
  • 99
  • 204
  • 1
    This is the one comment that actually answers the question asked (so far). – John F. Miller Nov 22 '11 at 04:57
  • 1
    Just one minor nitpick: the objects of `Hask` are the Haskell *types*, not the values. The arrows are the haskell functions having the respective types as the domain and codomain. – Lambdageek Nov 22 '11 at 17:02
  • @Lambdageek: Good call, fixed. – sclv Nov 22 '11 at 17:18
  • 1
    I hope it's OK that I accepted the other answer; I figured you already made tons of reputation on this one and that way there's a bit of a reward for everyone. Your answer is most appreciated! – Kerrek SB Nov 23 '11 at 18:12
19

As a compliment to Carl's answer, a Monad in Haskell is (theoretically) this:

class Monad m where
  join :: m (m a) -> m a
  return :: a -> m a
  fmap :: (a -> b) -> m a -> m b

Note that "bind" (>>=) can be defined as

x >>= f = join (fmap f x)

According to the Haskell Wiki

A monad in a category C is a triple (F : C → C, η : IdF, μ : FFF)

...with some axioms. For Haskell, fmap, return, and join line up with F, η, and μ, respectively. (fmap in Haskell defines a Functor). If I'm not mistaken, Scala calls these map, pure, and join respectively. (Scala calls bind "flatMap")

dcco
  • 75
  • 8
Dan Burton
  • 53,238
  • 27
  • 117
  • 198
  • 8
    I like this answer because although monads are *useful* to us as programmers primarily because of `>>=`, the (`fmap`, `join`, `return`) triple better illuminates what monads actually *are* (imo). When I finally understood what ["a monad is just a monoid in the category of endofunctors"](http://stackoverflow.com/questions/3870088/a-monad-is-just-a-monoid-in-the-category-of-endofunctors-whats-the-problem) actually *meant*, I was enlightened. – dave4420 Nov 22 '11 at 09:39
12

Ok, using Haskell terminology and examples...

A monad, in functional programming, is a composition pattern for data types with the kind * -> *.

class Monad (m :: * -> *) where
    return :: a -> m a
    (>>=)  :: m a -> (a -> m b) -> m b

(There's more to the class than that in Haskell, but those are the important parts.)

A data type is a monad if it can implement that interface while satisfying three conditions in the implementation. These are the "monad laws", and I'll leave it to those long-winded explanations for the full explanation. I summarize the laws as "(>>= return) is an identity function, and (>>=) is associative." It's really not more than that, even if it can be expressed more precisely.

And that's all a monad is. If you can implement that interface while preserving those behavioral properties, you have a monad.

That explanation is probably shorter than you expected. That's because the monad interface really is very abstract. The incredible level of abstraction is part of why so many different things can be modeled as monads.

What's less obvious is that as abstract as the interface is, it allows generically modeling any control-flow pattern, regardless of the actual monad implementation. This is why the Control.Monad package in GHC's base library has combinators like when, forever, etc. And this is why the ability to explicitly abstract over any monad implementation is powerful, especially with support from a type system.

Carl
  • 26,500
  • 4
  • 65
  • 86
6

You should read the paper by Eugenio Moggi "Notions of computations and monads" which explain the then proposed role of monads to structure denotational semantic of effectful languages.

Also there is a related question:

References for learning the theory behind pure functional languages such as Haskell?

As you don't want hand-waving, you have to read scientific papers, not forum answers or tutorials.

Community
  • 1
  • 1
nponeccop
  • 13,527
  • 1
  • 44
  • 106
5

A monad is a monoid in the category of endofunctors, whats the problem?.

Humor aside, I personally believe that monads, as they are used in Haskell and functional programming, are better understood from the monads-as-an-interface point of view (as in Carl's and Dan's answers) instead of from the monads-as-the-term-from-category-theory point of view. I have to confess that I only really internalized the whole monad thing when I had to use a monadic library from another language in a real project.

You mention that you didn't like all the "lots of examples" tutorials. Has anyone ever pointed you to the Awkward squad paper? It focuses manly in the IO monad but the introduction gives a good technical and historical explanation of why the monad concept was embraced by Haskell in the first place.

hugomg
  • 68,213
  • 24
  • 160
  • 246
  • I appreciate your first sentence (a great example of a concise definition), but perhaps my question wasn't clear enough: I am very happy with the notion of a categorical monad. I want to understand how a monad in functional programming is defined, explained in categorical terms. Or actually, explained in whatever terms you like, as long as it's clear, precise and succinct. *If* the explanation is easiest using categorical terms, then go for it. :-) If you think an explanation in terms of programming only is better, have a go, too. – Kerrek SB Nov 22 '11 at 14:23
  • Im sorry, that explanation is actually from a joke (`:/`). As for succinctness I think trying to summarize monads to just a single sentence is hard - you can give the precise interface definition (as others have already given in this thread) but then you miss the explanation of why worth going through this trouble in the first place. Dunno, I'm the kind of guy that only understands things after you can convince me there is a need for them to exist in the first place. – hugomg Nov 22 '11 at 14:31
4

Since you understand monads in the category-theoretic sense I am interpreting your question as being about the presentation of monads in functional programming. Thus my answer avoids any explanation of what a monad is, or any intuition about its meaning or use.

Answer: In Haskell a monad is presented, in an internal language for some category, as the (internalised) maps of a Kleisli triple.

Explanation: It is hard to be precise about the properties of the "Hask category", and these properties are largely irrelevant for understanding Haskell's presentation of monads. Instead, for this discussion, it is more useful to understand Haskell as an internal language for some category C. Haskell functions define morphisms in C and Haskell types are objects in C, but the particular category in which these definitions are made is unimportant.

Parameteric data types, e.g. data F a = ..., are object mappings, e.g. F : |C| -> |C|.

The usual description of a monad in Haskell is in Kleisli triple (or Kleisli extension) form:

class Monad m where
    return :: a -> m a
    (>>=) :: m a -> (a -> m b) -> m b

where:

  • m is the object mapping m :|C| -> |C|
  • return is the unit operation on objects
  • >>= (pronounced "bind" by Haskellers) is the extension operation on morphisms but with its first two parameters swapped (cf. usual signature of extension (-)* : (a -> m b) -> m a -> m b)

(These maps are themselves internalised as families of morphisms in C, which is possible since m :|C| -> |C|).

Haskell's do-notation (if you have come across this) is therefore an internal language for Kleisli categories.

dorchard
  • 1,198
  • 8
  • 15
4

I don't really know what I'm talking about, but here's my take:

Monads are used to represent computations. You can think of a normal procedural program, which is basically a list of statements, as a bunch of composed computations. Monads are a generalization of this concept, allowing you to define how the statements get composed. Each computation has a value (it could just be ()); the monad just determines how the value strung through a series of computations behaves.

Do notation is really what makes this clear: it's basically a special sort of statement-based language that lets you define what happens between statements. It's as if you could define how ";" worked in C-like languages.

In this light all of the monads I've used so far makes sense: State doesn't affect the value but updates a second value which is passed along from computation to computation in the background; Maybe short-circuits the value if it ever encounters a Nothing; List lets you have a variable number of values passed through; IO lets you have impure values passed through in a safe way. The more specialized monads I've used like Gen and Parsec parsers are also similar.

Hopefully this is a clear explanation which isn't completely off-base.

Tikhon Jelvis
  • 67,485
  • 18
  • 177
  • 214
2

The Haskell wikibook page has a good basic explanation.

Nightfirecat
  • 11,432
  • 6
  • 35
  • 51
none
  • 21
  • 1