Ask HN: What is a monad?
I'd like to start digging into functional programming beyond what is available in C# and Javascript, and began by reading a little about Haskell. There are a lot of mentions about something called Monads, which are part of category theory.
Can someone provide an explanation that would make sense to an experienced developer in the OOP world?
54 comments
[ 2839 ms ] story [ 602 ms ] threadhttp://www.rbjones.com/rbjpub/philos/classics/leibniz/monad....
The embedded type system of a programmatic monad remains unchanged despite the monad's combination into higher level structures - a somewhat Leibnizian characteristic.
The monad is the axioms outlined in the article. The applicability of the monad are the logical consequences of its axioms, but it is no more than its axioms.
Happy hacking!
Monads can be implemented in OO languages, like ruby: http://moonbase.rydia.net/mental/writings/programming/monads...
Tony Morris, on of the authors scalaz (which implements monads, among other things, in scala ): http://projects.tmorris.net/public/what-does-monad-mean/arti...
A one that was considered a very good explanation on the topic: http://blog.sigfpe.com/2006/08/you-could-have-invented-monad...
This is a good intro: http://homepages.inf.ed.ac.uk/wadler/papers/marktoberdorf/ba...
Be sure to mentally replace "monad" with "warm fuzzy thing" when reading it and it should make sense.
For example, that trick allows you to pass information from future (one of Wadler examples).
http://www.it.uu.se/edu/course/homepage/avfunpro/ht10/notes/...
OO is designed to hide the dangerous parts of the world from you. The dangerous parts of the world (or at least some dangerous parts of the world) are encapsulated inside little black boxes with well defined interaction points. If you interact only through those little boxes, you should be safe. For instance, a logger object gives you 1 methods: writeLog (I'll ignore logging levels). The details of actually writing logs are not your business, and you (in principle) don't need to worry about them.
Monads are stricter. A monad puts you into a box and only gives you a few interaction points with the outside world. You can do whatever you want in a monad, but you are never allowed to leave the box. Inside the logger box, you are permitted only pure functions (functions with no side effects) and writeLog.
So basically, in an OO world, code using a logger might call os.unlink("/var/log/myprogram.log"). This would interact in a harmful way with your logging mechanisms. In a monadic world, from inside the logging monad, you are not given access to os.unlink.
Thus, f: a -> Loggable b in the monadic world (where Loggable b is an b living inside the box) is safer than f: (Logger, a) -> b in the OO world.
But, more like sandbox type.
As an example, lists are monads. The operator for doing calculations with the value in a monad is >>= (pronounced "bind"). To double every item in an array, you could do:
(The syntax "\n -> [n2]" defines a function that takes one argument, n, and returns a list containing n 2.)There's clearly work going on behind the scenes to pass each value in the list to the associated function as "n", and then combine all the resulting [n * 2] lists into one big list of the same type as the original. But that's all transparent to the programmer. He only sees the interface that the monad offers.
Are Python list comprehensions monads?
The two operations that must be defined for a monad are:
• Return: You pass any value and it returns a monad encapsulating that value
• Bind: You pass a function taking an argument of the type wrapped by the monad and returning another value wrapped in the monad, and it returns a value of the monad
With these two operations, you can accomplish a surprising range of tasks. Python borrowed list comprehensions from Haskell, where they are based on monads — but in Python, they're kind of orphaned from their monadic roots.
This is not true for many commonly used monads, except for the IO monad. You can extract values from the list monad, Maybe monad, state monad, etc.
Put simply, a monad specifies how values can be wrapped in a 'box', and how such boxes are combined. For instance, Maybe is a box that can contains either a variable or nothing. In Haskell:
data Maybe a = Nothing | Just a
The Maybe monad specifies how expressions resulting in a Maybe are combined. Expressions are evaluated until/unless one of the expressions returns 'Nothing', and the value of the monad becomes Nothing.
Comparably, the IO monad specifies how IO actions are combined, the State monad combines expressions in such a manner to create 'state', etc.
We have tried to illustrate Monads with a Haskell-ish example here:
http://www.nlpwp.org/book/chap-words.xhtml#id3390030
Monads enable syntactic sugar. If you're getting started with Haskell, you'll notice that when you write code that does I/O, you use a weird imperative-looking syntax ("do notation") that looks different to the normal functional style:
'putStrLn "Hello"' doesn't actually print anything; it returns an IO value that, when interpreted by the Haskell runtime, prints something: that interpretation takes place when 'main' is run. The do notation is syntactic sugar for creating a sort of compound IO value that interprets as a bunch of actions rather than just one. The reason you can use do notation for IO but not for (all) other Haskell code is that IO values are monadic (which is another and possibly more useful way of saying "IO is a monad"): that just means that they behave in a certain way when combined (to produce that compound value) and obey certain laws to make the do notation well behaved.Monads are a design pattern to abstract away repetitive functional code. For example, if you write a lot of pure-functional code you sometimes end up having to pass around a 'state' parameter. If a function reads or writes from the state, then any function that calls it has to pass in the state, and so on. This leads to a lot of functions with an extra state parameter, many of which don't even care about the state except to pass it down the call tree. An improvement would be to write a higher-order function which took a function which didn't care about state and wrapped it to produce one that just passed the state through. The State monad encapsulates this wrapping and lets you clean up the rest of your code.
Monads are what's between the lines of an imperative program. Bourne shell scripts have the default error-handling rule that they ignore failing commands unless it's the last one executed, or put another way, they run in a monad that ignores errors:
But you can tell it to run instead in a monad which stops after the first error: Old-school Visual Basic has the opposite default, but you can make it behave like a shell script with "ON ERROR RESUME NEXT". Yes, VB had monads.Monads are a specific example of higher-kinded polymorphism, which is a very powerful and useful concept that's starting to enter the programming mainstream (examples are template concepts in C++ and LINQ in C# and .NET). Parametric polymorphism (List<String> in Java and C#, etc) means you don't have to write a 'reverse' function that works on lists of strings, and another 'reverse' function for lists of ints, etc; you can just write a generic reverse function that works on lists of any kind, because it doesn't need to know the details of the contained type, just how to iterate over a list. However, if you want to reverse an array, you still have to write a new 'reverse'. If your language supports higher-kinded polymorphism, you can write a generic reverse function that works on any kind of container, because all it needs to know is that the container has some well-behaved method of iteration.
(The LINQ example is a bit more subtle, because C# doesn't support higher-kinded polymorphism, but LINQ is a hard-coded exception to that rule. The cool LINQ syntax works for any type whi...
Then I try to combine them and my head explodes.
You don't need to understand Monads to understand Haskell but they're how you print "Hello world"?? Yeah. Your other example also seem pithy and worthy, and again leave me feeling like the result is utterly opaque. You've shown goodness and power and all but it feels like you're holding the real definition behind your back to make the magic look even more magical-er.
How's-about-ya-spit-it-out. What the heck's a monad?
I feel like I've gotten as far as thinking that a monad's like a little interpreter/pre-interpreter. You pass it something like raw code and it binds more meaning to the variables as well as change the context of execution etc, all before that code gets eventually interpreted. Kind of like how you pass fragments of code to Ruby functions and kind of like how c++ templates are parameterized by type.
Wikipedia says "A monad is a construction that, given an underlying type system, embeds a corresponding type system (called the monadic type system) into it (that is, each monadic type acts as the underlying type). This monadic type system preserves all significant aspects of the underlying type system, while adding features particular to the monad." http://en.wikipedia.org/wiki/Monad_(functional_programming) At least that definition doesn't leave me feeling like someone's said "I can't tell you but they're really great"...
Monads are basically a design pattern dealing with special data types. Let's say you're in some situation where there's nondeterminism—each function doesn't return just a value, but several possible values. To use a pseudo-C++-like type system, all of your functions have a signature like
where it returns a list of B's to represent every possible value. You want to chain these together, and the naïve way is So for every function, you have to repeatedly accumulate the possible values for every possible value so far. If you have higher-order functions, you can encapsulate this in a function like this which means the above example could be rewritten as Now, the type of bind looks something like which is to say it takes a function from a normal type to a "special" type—in this case a list—and applies it to a "special" type—in this case, every element of a list. In this case, we'd say that List, together with the bind function, is monadic. The Haskell types look more like The key here—and it's a simple example, so it's probably hard to see how it extends to the hype given—is that you've got a "special" kind of data and you're taking functions which operate on normal (non-special, in this case, non-list) data and writing functions to use them on special data with little work. The cool thing is that it's a really common pattern, which is why Haskell programmers mention it a lot.(Note: in Haskell, 'bind' is actually an operator written >>=, and the order of its arguments are reversed, so its type is
but there are reasons for writing it the way I did.)I didn't mean to "hold the real definition behind my back", just felt that others in this thread had explained the definition better than I could. I also wanted to make the point that the definition is not that important unless you actually want to implement your own monad.
You don't need to understand Monads to understand Haskell but they're how you print "Hello world"??
Yes, there's no contradiction here. The idiomatic and easiest way to write Hello World in Haskell involves some unusual, but fairly intuitive, imperative-looking syntax. That syntax only works because the Haskell IO API is monadic, but you really don't need to know that, nor to understand what a monad is, in order to print Hello World.
LINQ is very similar to Haskell's do-notation, and LINQ providers (LINQ-to-Objects, LINQ-to-SQL etc) are monadic, but you don't need to know what a monad is to write "from u in users where u.age > 21 select u.name". If you want to write your own LINQ provider, though, it's probably worth knowing the monad laws.
You'll see Haskell tutorials delay telling about the concept. There's a reason.
For a bird's eye of monads you can check this: http://www.reddit.com/r/programming/comments/64th1/monads_in...
If you are ready, read and do exercises in http://blog.sigfpe.com/2007/04/trivial-monad.html and then http://blog.sigfpe.com/2006/08/you-could-have-invented-monad....
A category is something like a set, but combining the objects with allowed operations. (How very OOP!) The available functions are first-class citizens (called arrows). The objects are the domains and ranges of the arrows, and their internal structures are not exposed. Arrow composition is associative when it is defined. (You can only compose an arrow if the range of one is the domain of the next.)
A functor is just a (natural) function on categories mapping both objects and arrows in a compatible way. Endofunctors map to the same category.
As each object in this category of endofunctors is a function we want to compose, we have to be given a way to do that. This is what that the monoid here does -- it's a way to describe the allowed ways of combining natural transformations, including any systematic tweaks to be done during the combination.
(The classical definition of a monoid is just a set with an associative binary operation with an identity.)
OK, a monoid in the category of endofunctors is an endofunctor F together with a natural transformation (the multiplication of the monoid) from F composed with F to F, and another natural transformation from id to F (called the unit). In Haskell F is the type constructor of the monad, the unit is called return and the multiplication is usually called join (and in the case of the list monad is also known as concat).
(Note that the definition of monoid needed here is not that of a set with associative binary operation, but the more general "monoid object in a monoidal category". Instead of a set S and a multiplication S x S->S, where x denotes cartesian product, we want a functor F and a multiplication F o F->F where o denotes composition. This is an instance of the general sort of monoid since the category of endofunctors is monoidal with respect to composition.)
So here it is: monads are just objects with overloaded and extended "." operator and with special function "return" that modifies object (in accordance with object meaning) and returns it's input value unchanged. That new operator allows us to bind return results if we want so. Overloading of "." allows us to implement various interesting operations - passing state, executing optional computations, executing non-deterministic computations, probabilistic computations, etc.
You incapsulate the meaning of computation inside object, so you can pass it to some evaluator without that evaluator knowing that you pass him non-deterministic computation instead of monte-carlo monad or vice-versa.
So monads allow sequences of actual actions to be packaged together and given preconditions and then executed in a safe manner (perhaps with an eye to concurrency). You get to maintain the exquisite purity of functional programming while still writing software that, you know, gets stuff done occassionally.
If you were looking for an explanation of the mathematical concept though, sorry, ain't got a scooby.
So the code (quoting from samstoke's hello world):
would get translated to: Note that this makes the order of operations explicit, and that no World needs to be modified. Note also that now main has to take and return one of these World objects, so that a World needs to be threaded through all computations that will interact with the World (just like IO actions can only be executed from within other IO actions).A monad lets you thread implicit state through a computation.
Monads in category theory are an algebraic device for embedding a category--usually a cartesian closed category--of types of values into a new category with types of computations. However, the correspondence between Haskell monads and category monads are related by a series of adjunctions.
Suppose that C is a cartesian closed category and M:C->C is a monad with natural transformations e:1->M (the unit) and u:MM->M (the multiplication).
We assume a fixed choice of products and compatible exponentials: for each type A of C,
Here's the adjunction The final map is given by currying, but it can also be motivated as follows if you think of the exponentials as internal hom sets. If g:A -> MB is in C, so that g:A->B is in the Kleisli category C^M, then u_{MB}oM(g):MA->MB. We can write this as the lambda term \lambda x\in A A -> MB.u_{MB} oM xThis lambda term corresponds to composition in the Kleisli category C^M of C, and belongs to the internal language LL(C), the simply typed lambda calculus determined by C. Under the Curry-Howard-Lambek correspondence, the lambda term corresponds to the required map of C.
When a language explicitly talks about monads, it's because it lets you overload that operator, i.e. it let's you give alternative definitions of what it means to chain statements together.
Haskell excels as a functional language because it has excellent piping, Monads are just another form of piping with particularly great syntactic and psychological properties. They act as wrappers around a direct type and setting the return type of a function as a monadic type (such as IO () or [Int] or Maybe Bool) means that the primary type is () or Int or Bool, but there's something special being passed along as well.
In practice this saves typing since you don't explicitly pass the special monadically-hidden information. It also psychologically lets you think of simple types being wrapped in contexts which have certain properties. Some contexts can be unwrapped, some cannot. Some contexts can transform into other contexts directly, some cannot. Learning the behavior of each monad independently teaches you about these behaviors and then becomes important in advanced Haskell programming.
When learning, avoid them. Learn how to use IO by rote and ask in IRC about the confusing type errors that will arise. They usually translate as "you tried to combine two pipes which don't fit, so that monadic special sauce was lost". Part of learning Haskell is learning all of the joints and adaptors which help you to combine types effectively (including monads).
When you have a firm grasp of using compositions and maps and filters, start with the Maybe monad. Implement it and use all the general monad adaptors on them. Then learn the basic State monad because it makes the special sauce very explicit. Learn IO last because it's really a special case and should never be introduced as a monad.
Monads are sequential processes, which are combined to make bigger processes. getLine is a monad, so is putStrLn "hello". You can combine two monads into a bigger monad using the >>= operator, which would be the "means of combination" which is extensively discussed in the Structure and Interpretation of Computer Programs lectures. Simplest monad program I can think of is echo = getLine >>= putStrLn.
I learned monads by doing simple stuff like guess the number and hangman, first writing them in the do-notation (syntactic sugar for a mini-imperative language) and then converting that to concrete notation using >>=.
Monads are not only useful for IO, but also other sequential processes such as parsing, pretty printing, binary file io and stateful inside but functional outside algorithms (ST monad).
Disclaimer: this was written by a Haskell newb, recently introduced to the wonderful world of Monads.