7 ms·
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?
- brudgers 16y agoLeibniz on Monads: http://www.rbjones.com/rbjpub/philos/classics/leibniz/monad.htm http://www.rbjones.com/rbjpub/philos/classics/leibniz/monad....
- samstokes 16y agoUnfortunately "monad" gets used in a few contexts unrelated to the sense the OP is asking about. Similarly, the (cancelled) TV series Caprica recently started using "monad" to mean "monotheist".
- brudgers 16y agoOn the other hand, it seems that if one is willing to propose a similarity between one of the cornerstones of rationalism and the misuse of "monad" by a fictional character on a canceled television series, one might be more open to seeing more direct lines of intellectual descent from an inventor of the calculus to functional programming. The embedded type system of a programmatic monad remains unchanged despite the monad's combination into higher level structures - a somewhat Leibnizian characteristic.
- deleted 16y ago[deleted]
- deleted 16y ago[deleted]
- troutwine 16y agoThe Wikipedia has a very good treatment: http://en.wikipedia.org/wiki/Monad_(functional_programming) http://en.wikipedia.org/wiki/Monad_(functional_programming) 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!
- DanielRibeiro 16y agoMonads are (quote) elephants: http://james-iry.blogspot.com/2007/10/monads-are-elephants-part-3.html http://james-iry.blogspot.com/2007/10/monads-are-elephants-p... Monads can be implemented in OO languages, like ruby: http://moonbase.rydia.net/mental/writings/programming/monads-in-ruby/00introduction.html 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/artifacts/1.0/chunk-html/index.html 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-monads-and.html http://blog.sigfpe.com/2006/08/you-could-have-invented-monad...
- deleted 16y ago[deleted]
- pwpwp 16y agoA cheap and unexciting trick for passing a value through a couple of functions. (Monads are cool, but it's important to understand that there's nothing, nuttin', whatsoever fancy about them, so I like to call them a "cheap trick".) This is a good intro: http://homepages.inf.ed.ac.uk/wadler/papers/marktoberdorf/baastad.pdf 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.
- thesz 16y agoActually, the effects of that trick are nothing less than exciting. For example, that trick allows you to pass information from future (one of Wadler examples).
- deleted 16y ago[deleted]
- clofresh 16y agojQuery is a monad: http://news.ycombinator.com/item?id=439116 http://news.ycombinator.com/item?id=439116
- sbhat7 16y agoSlides from functional programming class might clarify things a bit [PDF]. http://www.it.uu.se/edu/course/homepage/avfunpro/ht10/notes/glimming-4up.pdf http://www.it.uu.se/edu/course/homepage/avfunpro/ht10/notes/...
- yummyfajitas 16y agoIt's a design pattern for encapsulation, with similar goals to OO but different methods. Rather than telling you what a monad is, I'll just tell you the goal. 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.
- StavrosK 16y agoSo, a sort of sandbox function?
- thesz 16y agoYes. But, more like sandbox type.
- StavrosK 16y agoHmm, I see. Does it also execute code, like a sort of exception handler, or is it just for limiting/allowing access to scope?
- chc 16y agoA monad is a type that has certain associated functions — to wrap values in the monad and do calculations on what's inside. The type itself obviously cannot execute code, but the associated functions obviously do. Monads can be used to implement exceptions. 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: [1, 2, 3] >>= \n -> [n * 2] (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.
- ChadHydro 16y agoMonads are a means of guaranteeing program sequentiality and maintaining state.
- lincolnq 16y agoI wrote some stuff about monads on HN a while ago that some people found helpful: http://news.ycombinator.com/item?id=247446 http://news.ycombinator.com/item?id=247446
- samstokes 16y agoMonads are red herrings, if what you're interested in is getting started with functional programming (or even Haskell specifically). It's an unfortunate flaw in the Haskell literature that makes it seem like you have to grok monads to learn Haskell; you don't. 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: main :: IO () main = do putStrLn "Please enter your name" name <- getLine putStrLn ("Hello " ++ name ++ "!") '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: cat nonexistent.txt # prints an error message echo Done. # still executes, prints "Done." # script returns success But you can tell it to run instead in a monad which stops after the first error: set -e # change the monad, i.e. the error-handling rule cat nonexistent.txt # prints an error message echo Done. # never runs # script returns failure 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 which provides certain operations and behaves in a certain way - which just happen to coincide with the requirements for the type to be monadic.)
- deleted 16y ago[deleted]
- g__ 16y agoDON'T start functional programming with monads. Familiarize with currying, pattern matching, how to create data types in Haskell, using recursion instead of loops, higher order functions, list comprehensions, type classes, polymorphism in Haskell (different than subtyping in OOP). Ignore monads for a while. To understand monads you must have a good grip of those concepts. You can start with http://learnyouahaskell.com/chapters http://learnyouahaskell.com/chapters. 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_python_in_production_code_you_can_and/c02u9mb 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 http://blog.sigfpe.com/2007/04/trivial-monad.html and then http://blog.sigfpe.com/2006/08/you-could-have-invented-monads-and.html http://blog.sigfpe.com/2006/08/you-could-have-invented-monad....
- wnoise 16y agoWhat, no one is giving the standard answer of "a monad is a monoid in the category of endofunctors?" 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.)
- keefe 16y agoand here I was ready to make a snarky comment about a monad being a specific instance of a polyad
- omaranto 16y agoThe paragraph starting "As each object in this category..." made no sense to me. I can explain the what a monoid in the category of endofunctors is, how it relates to a Haskell monad and maybe you can explain what you meant. 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.)
- thesz 16y agoMy friend told me recently that he invented monads in Javascript: result = monadicObj .action1(arg) .action2(arg2); I told him that he needs variable binding operations for fully fledged monads: result = monadicObj . x <- action(arg) . y <- action2(x,arg2) . action3(x,y,arg3) . return (x+y); Otherwise, his invention is much more like Applicative, because we cannot pass values between actions. 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.
- Tycho 16y agoFrom my limited understanding garnered by listening to SE Radio, monads are basically a way for Haskell programs to execute actions (rather than simply computing values), so that your program can ultimately DO something like write to a file. As you probably know, the functions aren't supposed to contain any side effects: you don't want something unexpected to happen when you just want to calculate a value. It would be like a spreadsheet that printed out a page every time you entered a certain cell - might make sense in a one-off situation but in the long run it's just inviting trouble. 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.
- lallysingh 16y agoThe short answer is to read chapter 14, probably more than once, before it makes sense. It took me 2 times: http://book.realworldhaskell.org/read/ http://book.realworldhaskell.org/read/
- okmjuhb 16y agoLet's say you wanted to implement I/O in a language without side effects. You could put all your interactions with the world in a special "World" object. Every time you called world.putString("foo"), you'd get back a new world object that represents the state of the world with "foo" having been written out. So the code (quoting from samstoke's hello world): main :: IO () main = do putStrLn "Please enter your name" name <- getLine putStrLn ("Hello " ++ name ++ "!") would get translated to: main :: World -> World main world = let newWorld = putStrLn world "Please enter your name" in let (newerWorld, name) = getLine newWorld in let newestWorld = putStrLn newerWorld ("Hello " ++ name ++ "!") in newestWorld 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.
- ChristianMarks 16y agoMoggi used monads in category theory to define computations with side effects in functional programming. The basic insight is that in addition to the values of various types in functional programming, there are "computations" of various types. Examples of "computations" would be exceptions or continuations. Each monad defines for each value type a computation "containing" that type, and the whole type system of values you started with can be embedded in a new type system with new computation types. 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, A x ( ) -| [A -> ( )] Here's the adjunction MA -> [[A->MB] -> MB] --------------------- MA x [A -> MB] -> MB --------------------- [MA -> MB] x MA -> MB ----------------------- [A -> MB] -> [MA -> MB] 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 x This 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.
- fab13n 16y agoIt's the operator that allows to chain two statements together. It's written ";" in Pascal, and is often implicit in other languages. 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.
- tel 16y agoThere are already a number of excellent answers, but I'll try my hand. You don't know something until you can explain it 3 different ways. 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.
- exDM69 16y agoI'll have my stab at making a short explanation without code or lots of technical stuff. So here's some handwaving that may contain mistakes: 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.