The “What Are Monads?” Fallacy
two-wrongs.com
two-wrongs.com
The software development community is by and large much more pragmatic and focused on solving real-world problems. They have an easier time understanding concepts and code examples when explained in the context of real-world problems.
So when the Haskell people try to explain monads, they start with the abstract definition, the monadic laws and so on, and they focus on explaining the concept of a monad, rather than what they are practially useful for. Even the many infamous monad-metaphors (its like a spacesuit! No its like a burrito!) try to find a metaphor for the abstract concept of a monad, not for any practical use. For the typical developer this might seem like a lot of mathematical wanking for little benefit.
The language F# seem to have a more 'pragmatic' culture. 'Monads' are called 'computation builders' in F#, and the equivalent to do-notation is called 'computation expression'. Yeah it is just naming, but it shows a focus on the use of monads rather than on the underlying mathematical concept.
A typical F# example of the use of monads - sorry, computation builders is the Async monad:
let AsyncHttp(url:string) =
async {
let req = WebRequest.Create(url)
let! rsp = req.GetResponseAsync()
use stream = rsp.GetResponseStream()
use reader = new System.IO.StreamReader(stream)
return reader.ReadToEnd()
}
This example fetches a resource over http without blocking. It is immediately obvious why this is useful. After all, similar functionality was recently added to C# through the keywords 'async' and 'await'. But in F# it didn't require the addition of new keywords but could be implemented as a library, due to support for monads in the language.This is usually because Haskell functions are really short. For example:
compose f g x = f (g x)
We could write this with more descriptive variable names, but there are only 3 variables and they're only in scope for one very tiny line: compose outerFunction innerFunction argumentForInnerFunction = outerFunction (innerFunction argumentForInnerFunction)
There are certain conventions as well; if a variable must be present, but isn't used, it gets called `_`: first (x, _) = x
Lists tend to get a plural "s" on their name: elem x xs = any (map (x ==) xs)
> So when the Haskell people try to explain monads, they start with the abstract definition, the monadic laws and so on, and they focus on explaining the concept of a monad, rather than what they are practially useful for. For the typical developer this might seem like a lot of mathematical wanking for little benefit.This is because functional programmers tends to spend the most time on writing generic, abstract, re-usable libraries. Particular applications are just thin veneers on top of these libraries. For example, I might spend most of my time writing generic, abstract code to deal with tuples. To make an application, I can just pick and choose the library code I want to use:
type Name = String
type Address = String
type Quantity = Int
type OrderID = Int
type SKU = Int
type Customer = Tuple Name Address
type Order = [Tuple SKU Quantity]
type Invoice = Tuple Customer Order
Given that I'm using Tuples for Orders, Invoices and Customers, the time I spent writing abstract code to deal with tuples wasn't "a lot of mathematical wanking for little benefit".The time spent writing generic, abstract monad libraries isn't wasted either; by picking and choosing which monads to use, our application can automatically get error-handing, non-determinism, backtracking, exceptions, state, software transactional memory, etc.
For values:
f, g, h: functions
x, y, z: numbers or generic values
m, n, o: monadic values
For polymorphic types: a, b, c: arbitrary value type
s, t, u: state or structure
f, g, h: functor (possibly applicative)
m, n, o: monad
i: index
There are probably some others that I'm not thinking of, too.EDIT: Thanks for the responses. I'd love to study any resources that you found useful when learning Monads. Do you know of any?
I can also give you a very succinct definition of a monad, or a succinct example, but I doubt you'd understand them until you've seen many examples in different domains.
(If you want examples or defn, there are many web pages that have them.)
Similarly learning about the either monad might be easier if you start from the concept of chaining error handling, as in this tutorial: http://fsharpforfunandprofit.com/posts/recipe-part2/, and then show how it can be done with monads.
But I agree with the 'monad tutorial fallacy' that you'll only learn it once you actually try to write code using it and see if it works the way you thought it would.
Really the problem, alluded to in the blog post, is that the worst thing you can possibly do to 'explain' monads is to try to remove them from their context. They aren't fruit, they aren't tupperwear, and a bunch of the incarnations of them aren't useful in imperative programming, so trying to explain them in those contexts is futile.
In the terminology of the blog post, this is like asking what a musical instrument technically is, and being told to go learn the piano and violin - from someone else, no help here - and stop bothering the busy blogger.
Sure, maybe that's a little unfairly meta if you really want to know, but it is what it is.
That is way out of scope of this article, but perhaps suitable for five other separate articles. I'll have to think about it! Meanwhile, I'm sure you can Google search for Stack Overflow questions on Maybe, Either, List and other monad types to get used to them.
You can imagine it a little like walking up to a musician and asking, "Will you please teach me the musical instruments?" The answer you get will be filled with counter-questions: "Do you know any musical instrument? What kind of instrument are you interested in? Can you read sheet music?"
(Or, for that matter, try asking an OOP programmer, "Teach me the Gang of Four patterns, please!" It will elicit a similar response, not a 15-page blog post. ;) )
So as an intro it's a fine outline. Now get cracking on writing those 15 pages. :) Break it down into 5 parts. I'll upvote every one.
Make it suitable for someone coming from a language that doesn't have Monads. After all, it's a feature. If it can be learned - as you imply a way to do - then you can show and teach it, just as you've outlined.
(By the way, the difference between what you've just written of 'walking up to a musician' is that a student didn't ask you - you took it upon yourself to show a superior alternative to other people's blog posts on the subject. :))
So get cracking :)
Note: originally rather than post a critical comment here, I tried to email you, but didn't find an email address on your site, not even under "about" where you introduce yourself in two paragraphs - including your first name and city. Maybe add an email address there :)
Most languages either have or support particular examples of Monads, but what is missing from many is the ability to write code that works on all Monads.
Writing a Monad tutorial is pretty cliche now, because basically everyone who finally gets what the fuss was all about then blogs their own way of explaining it (guilty of this myself), so I'm not at all surprised that the author of this post didn't want to add yet another to pile.
I personally don't understand them.Some people told me it's a bit like "reversed" generics,some others pointed me at promises in Javascript which are "monadic".
I guess I don't understand them because I work with languages that make them either hard to implement or totally unnecessary.
E.g. you could use monads in JavaScript, but it would probably be simpler to solve the same problem without monads.
doThing1().then(function (thing1Result) {
doThing2(thing1Result).then(function (thing2Result) {
doThing3().then(function() {
doThing4(thing2Result + thing1Result).then(function (res) {
console.log("I did a lot of things. The answer is: " + res);
}
}
}
}
Basically, at each stage we're calling a function which may or may not return immediately, and saying "whenever you're done calculating, pass your result into this function I'm giving you here." Similarly, in monadic computation, you sequence a series of "actions" together by passing each a function that determines what to do based on the output of the previous one. In Haskell, the above fake code would be written like this: doThing1 >>= \thing1Result ->
doThing2 thing1Result >>= \thing2Result ->
doThing3 >>= \() ->
doThing4 (thing2Result + thing1Result) >>= \res ->
putStrLn ("I did a lot of things. The answer is: " ++ res)
So you can see the `>>=` acts like the `then` function we saw before, and each time we're passing in a new function (indicated with a backslash, which resembles a lambda). And since this kind of thing is so common, there's a syntactic sugar for all of this: thing1Result <- doThing1
thing2Result <- doThing2 thing1Result
doThing3
res <- doThing4 (thing2Result + thing1Result)
putStrLn ("I did a lot of things. The answer is: " ++ res)
Hopefully it's simple enough to see the correspondence between the above snippet and the one before it; the two are essentially identical.Now the really cool trick is that the same concept holds up for any monadic computation; that is, any situation in which we have a series of steps, executing in a well-defined order, and at each step we have the ability to "examine" what the previous step did in some way. Thus, for example, we can model a series of fail-able computations, where the failure of any one in the chain should cause the chain to stop at that point; or a series of actions that affect a background state in some way, or a chain of effectful computations like IO, or any number of other things -- the abstract idea tends to pop up all over the place, which is one of the great powers of type classes in general: they give you tools that you can use all over the place, even in vastly different arenas.
1. The three Monad laws, which have been beaten to death.
2. do-notation. You've started to learn Haskell, and you know the let-in syntax for introducing variable bindings, and suddenly you get hit with two NEW syntaxes: the let-but-no-in syntax, and the weird <- stuff. How do these syntaxes relate, and why (if?) are they all necessary? Also you just lost fifteen minutes because that line has a tab instead of spaces, the "last statement must be an expression" nonsense, etc.
3. Monadic APIs, especially IO. You can go through an entire Monad tutorial and be left wondering why you need category theory to get main's argv. Not to mention all of the duplication (mapM, filterM, zipWithM, etc).
Tutorials tend to focus on #1, but in my journey I found #2 and #3 to give me the most difficulty.
In most industrial languages, integers, floats and strings are Additive, because these things support the '+' operator.
Monads are at the same level of "concept" as Additive. Something is a monad if it has a set of operators that map to the Monad concept. The level of abstraction you need to be at, mentally, is "supports a specific set of operations with specific rules". A lot like an interface, but at the type level.
It is definitely a single concept, but there are variations on it, like Functor and Applicative, which are related. The core concept is adding a layer of indirection between a value and application of a function to the value. What the indirection does is the chief distinguishing feature of the monad. A Maybe monad only applies the function if the value is not None, for example. A List monad applies the function to each value in the list. The IO monad, on the other hand, logically stores the function and keeps it for later - the result of computing a pure functional Haskell program returning IO is an imperative program, which is then executed. That's how Haskell gets its side-effects in a pure fashion.
Its purpose here is to focus on the right level of abstraction when thinking about what a monad is, particularly when coming from languages like Java, C++, C#, etc.
1. bind(return(a), f) = f(a)
2. bind(m, return) = m
3. bind(bind(m, f), g) = bind(m, x -> bind(f(x), g))
That's all. Any pair of functions with those properties is a monad.The list monad represents nondeterministic computation ("nondeterministic" in the sense of representing all possibilities, not in the sense of picking a random one).
List:
return x = [x]
bind xs f = concat (map f xs)
Maybe represents computation with the possibility of failure. Maybe:
return x = Just x
bind Nothing _ = Nothing
bind (Just x) f = f x
State carries some data that can be read and updated in the context of the computation. State:
return x = \ s -> (x, s)
bind m f = \ s -> case m s of (x, s') -> f x s'
A Parser, from parsec, is a bit complicated internally for flexibility and error handling, but the gist is that it represents a parser action that may consume a portion of the input stream and produces a value. Parser:
return x: a parser that consumes nothing and produces x
bind m f: a parser that runs parser m, passes the output to
function f, and runs the resulting parser
Functions that all take the same type can be treated as a monad. This is often codified into Reader, to make things clearer. ((->) r):
return x = \ _ -> x
bind m f = \ r -> f (m r) r
And of course famously IO, representing actions that produce a value and may interact with the world at large, forms a monad. IO:
return x: an action which does nothing and produces x
bind m f: an action which, when executed, executes m, applies f
to the value produced, and then executes the result of fLet the type "Parser a" represent a parser that produces an "a", after consuming some (or no) input.
(In Haskell, lowercase letters are used for polymorphic types; Parser Integer is a parser that produces an Integer, Parser String a parser that produces a string, and so on. Any concrete value will be of some more specialized type, but functions can work on the polymorphic version if they don't rely on it being something more specific.)
Note that parsers may also fail, and give up on parsing further input, instead returning information about how it failed.
To run a parser against some input, we can do something like:
case (parse someParser inputString) of
ResultFailure errorString -> do something with error string
ResultSuccess value -> do something with value
where parse :: Parser a -> String -> Result a
data Result a = ResultFailure String | ResultSuccess a
We can put together a lot of things of this type. The simplest returns just a fixed thing and doesn't even look at the input. return :: a -> Parser a
So the expression, parse (return 5) inputString
would reduce to ResultSuccess 5, regardless of the input.We can also have things that return the next character, whatever it is:
anyChar :: Parser Char
parse anyChar "f" -- ResultSuccess 'f'
parse anyChar "7" -- ResultSuccess '7'
parse anyChar "" -- ResultFailure "premature end of input"
Or we can have something more restricted, like... oneOf :: [Char] -> Parser Char
abc = oneOf ['a', 'b', 'c']
parse abc "a" -- ResultSuccess 'a'
parse abc "d" -- ResultFailure "unexpected 'd'"
And we can have more sophisticated things: natural :: Parser Integer
So now... where does "monad" come in?Well, when we go to build a new parser out of these components, we need some way of combining them. We can do our parsing explicitly...
parseWithLeftovers :: Parser a -> String -> (String, Result a)
parseTwoIntegers input = case parseWithLeftovers integer input of
(_, ResultFailure errorString) -> ...
(input2, ResultSuccess int1) -> case parseWithLeftovers whiteSpace input2 of
(_, ResultFailure errorString) -> ...
(input3, ResultSuccess _) -> case parseWithLeftovers integer input3 of
(_, ResultFailure errorString) -> ...
(_, ResultSuccess int2) -> return (int, int2)
It should be plenty obvious why we don't want to do that every time. Let's factor out the boiler plate. The question is what that looks like...What if we set it up so those results could be collected and passed to an arbitrary function? That could let us write something like...
parseTwoIntegers = (,) <$> integer <*> (whiteSpace *> integer)
While you may not understand the symbols, I expect you'll agree that's quite a bit more readable.But that still doesn't actually require monads. <$> is a synonym for fmap, the two operators containing asterisks are from Applicative. Can we do everything we might want with these, without getting crazy explicit and chaining parsers by hand again?
Well, let's look a little closer at what's going on above. Specialized for clarity, the above operators have the following types:
(,) :: a -> b -> (a, b)
tuple operator - takes two arguments, makes a tuple out of them
(<$>) :: (a -> b) -> Parser a -> Parser b
"fmap" - applies a function to the result of a
parser, making it into a parser that does the
same thing but returns the modified result
(<*>) :: Parser (a -> b) -> Parser a -> Parser b
"ap" - takes a parser *producing a function*, and a
parser producing a value, and gives us a parser
that applies the function to the value
(*>) :: Parser a -> Parser b -> Parser b
Takes two parsers, runs both, returns the result of the second
Walking the above expression from left to right, we see... (,) :: a -> b -> (a, b) -- tuple operator
(,) <$> :: Parser a -> Parser (b -> (a, b))
note that the partial application of (,) *inside*
the parser gives us a parser returning a function
(,) <$> integer :: Parser (b -> (Integer, b))
we've picked our "a" and are left with a parser
returning a function - a job for "ap"
(,) <$> integer <*> :: Parser b -> Parser (Integer, b)
It should be reasonably apparent how the bit in
parens reduces, so skipping ahead...
(,) <$> integer <*> (whiteSpace *> integer) :: Parser (Integer, Integer)
It's easier - and not wrong - to think of "f <$> ... <> ... <> ..." as "apply this function to these wrapped values, giving me a wrapped result" - but the above is how that happens, and following it is a bit necessary for this next bit...What if we want to write
readNChars :: Parser [Char]
where the parser first reads the number of characters to read, and then reads that number of characters?Looking at the above operators, there's something that the function arguments (wrapped or not) have in common: none of the function arguments return a Parser. So the functions can't dictate what is parsed. That's what we fix next:
(>>=) :: Parser a -> (a -> Parser b) -> Parser b
"bind" - takes a parser, and a function that
returns a parser, runs the first parser, feeds the
result into the function, and runs the resulting
parser
This, then, allows us to say things like: parseCountItems :: Parser a -> Integer -> Parser [a]
parseCountItems p i = sequence (genericReplicate i p)
readNChars :: Parser [Char]
readNChars = integer >>= parseCountItems anyChar
Haskell programmers care that it's a monad for three reasons. First, communicative value - the pattern comes up a lot and it's useful to be able to quickly convey what's going on. Second, there are actually a number of useful functions that can be applied to any monad. For instance, mapM :: Monad m => (a -> m b) -> [a] -> m [b]
filterM :: Monad m => (a -> m Bool) -> [a] -> m [a]
when :: Monad m => Bool -> m () -> m ()
foldM :: Monad m => (a -> b -> m a) -> a -> [b] -> m a
Finally, do notation. Haskell provides some syntactic sugar that turns do
statement1
var <- statement2
statement3 var
into statement1 >>= \ _ -> statement2 >>= \ var -> statement3 var
The above "readNChars" could be rewritten: readNChars = do
cnt <- integer
sequence (genericReplicate cnt anyChar)
Do notation can often be clearer for complicated monadic expressions.Quite liked the post, nevertheless..
Sure it's possible to reduce LoC and look clever with ever more complex representations of computational structures, but it's another thing to write supportable code that's straightforward to debug, improve and maintain.
If someone wants to use a "research" language in production and/or want perpetual job security, there are plenty of languages for those requirements too.
(There's never a perfect Turing power language for anything, only better fits than others. Clarity for a new-hire reader should be most valued goal after functionality.)
Monads are not a big deal. Indeed they are so much of a not big deal that I expect this is a big part of the problem learning monads. People expect them to be something difficult and exotic, and go looking for hidden depths where there aren't any. I know I did when I first learned them. Eventually you break through and realise there is no hidden mystery. It's just a data type with a few functions, and they happen to be usable in a wide variety of contexts. That's what this blog post is trying to explain.
Finally, you can teach monads to new hires in a very short period of time. We do in our training courses.
If I were to recommend a basic path to understanding monads, I'd say do this:
1. Understand `map` in the context of lists. This can be done in Ruby or Scala very easily if you don't want to get into Haskell directly.
2. Learn about the Maybe monad (or Option in scala). Understand what mapping an Option or a Maybe means. A simplified explanation is to compare it to a list of either length 1 or 0.
3. Learn about the IO monad in Haskell. Understand how IO monads can compose. At this point, it's ok to just say magic happens and the compiler then cause a single IO monad (the result of composing multiple IO monads) assigned to main to execute and the side effects will happen.
At that point, you've got a general understanding of how to use monads. It will actually take you pretty far.
One key point that might be a hangup is going from `map` meaning "apply this function to every element and return a new list of the results" to `>>=` meaning "apply this function as dictated by the monad and return the result". It's probably good enough to acknowledge that `map` is a simplified case of `>>=`.
In any case, as the linked article says here, you should be able to understand specific Monads fairly quickly. Perhaps truly understanding monads means knowing when to create new monadic structures but that's hardly a prerequisite to being productive with monads.
I believe that's a similar point to the article. It's easier to understand how to use specific monads than to understand the mathematical definitions of functors and monads. Knowing `fmap` is essentially distributive isn't necessary to use functors and get a feel for what they provide.
I think you were unclear about what behavior belongs to monad, in a way that will confuse newcomers.
"map" (or "fmap") belongs to Functor; monads have it because they are functors.
I agree that starting with the laws doesn't necessarily makes the most sense, and that they're not necessary (though can be valuable) for use of these things... but you do need to introduce the laws early enough that they're understood by the time someone goes to write their own instances of the relevant typeclasses - otherwise they're going to get bit by something that assumes the laws hold, and they're not going to understand why.
But other uses of monads, like say monadic parsers could be useful in other languages. And list comprehensions is also based on a monad in Haskell - this functionality is clearly useful in many other languages.
But without some kind of syntactic sugar (like do-notation in Haskell) the use of monads becomes far to cumbersome, and it ends up being easier to solve the same problem in an ad-hoc manner.
Suppose we want a function that returns C = A + B, but only if A and B both exist. Otherwise C cannot be set with a meaningful value.
In an imperative language (python-esque?)I might do something like:
if A != NULL && B != NULL:
C = A + B
else:
C = NULL
in Scala: val C = for {
a <- A
b <- B
} yield a + b
What's the difference? In this example it is largely syntax, but let's do something with C. D = [1,2,3,4,5]
E = []
if C != NULL:
E = [x*C for x in D]
else:
E = D
So now we've got some complex logic. If C is set, then we want to multiply every element in D by C and assign the result to E.Without monads, I have to explicitly check for C == NULL before doing anything with it. The compiler isn't going to enforce that so it's possible I forgot to check and I segfault or NPE. Here's the monadic version:
val D = List(1,2,3,4,5)
val E = (for {
c <- C
x <- D
} yield c*x).getOrElse(D)
With an Option monad, I must use C inside the for comprehension. This is enforced by the compiler. If C is None, then cx won't execute and the for comprehension will return None. `getOrElse` on None just returns whatever was passed in, which in this case is D.So what did we gain? Again, it might just look like syntax. We swapped an `if C != NULL` and and `else` for a `c <- C` and a `getOrElse`. We actually gained some strong compiler guarantees.
Sort of a basic example and it might not be completely straightforward at first, but in my opinion once I understood how to effectively use monads (like Option and Try in Scala) my ability to simplify complex logic and be confident that it was correct increased.
EDIT: Haha... I botched my final scala example. That doesn't compile... something like:
val E = C.map{c => D.map(_*c)}.getOrElse(D)
would do the job.That's not true. It could still be useful to build up descriptions of IO that should be executed later, and an IO monad would be a fine way to do that in a language that provided the necessary capabilities to make that convenient.
Curious to know how as I have seen lots of people claiming jQuery to be Monad ? jQuery neither has any laws to govern it nor it has bind or inject interface.
It's clarity of explanation that makes anything teachable &| learnable.
[0] https://www.youtube.com/watch?v=xKRndVoo2ms
All signs of superhuman nature appear in man as illness or insanity. ~ Nietzsche
See: https://medium.com/javascript-scene/the-two-pillars-of-javas...
Whilst it's easy to see what a simple line of code is doing, it's not necessarily easy to see why it's being done, or to understand how a codebase made of simple lines works. An extreme example of this is machine code, where every instruction is incredibly simple, but trying to work out what the whole thing's doing in order to debug it can be very hard.
As a mere mortal, I appreciate monads and the simplicity they bring to my code.
---
We know how operators (add, substract, multiply,...) work on integers. example: 5 + 6 = 11.
Now let's add some extra state/dimension to integers. Let's assume this extra state is ROCK, PAPER or SCISSORS.
Here are possible values:
5_ROCK
6_PAPER
999_SCISSOR
...etc...
---
What is the result of 5_ROCK + 6_PAPER ?
There is no answer unless someone defines it. That's what a monad does. In this case I am deciding that 5_ROCK + 6_PAPER = 11_PAPER
The way MY monad works is to use the operator on the integer portion ( 5 + 6) and then use the winner of ROCK, PAPER, SCISSORS game as the non-integer portion.
3_ROCK * 4_SCISSOR = 12_ROCK
8_SCISSOR / 2_PAPER = 4_SCISSOR
...etc...
data RPS = Rock | Paper | Scissors
data IRps = IRps Integer RPS
fight Rock Paper = Paper
fight Rock Scissors = Rock
fight Paper Scissors = Scissors
fight Rock Rock = Rock
fight Paper Paper = Paper
fight Scissors Scissors = Scissors
fight x y = fight y x
instance Num IRps where
IRps x x' + IRps y y' = IRps (x + y) (fight x' y')
Of course, with the lack of associativity, I'd weakly discourage a Num instance too, but that's not adhered to perfectly already.>This is like someone new to a language with regular expressions asking what a regular expression, is, or someone new to object oriented programming asking what a class or object is, or someone new to functional programming asking what functional programming is, or someone new to node.js asking what node.js is, or someone new to programming asking what a program is.
>What's _wrong_ with you people? These are horrible questions. I refuse to answer them, and you should know better than to ask. Yes, I could illustrate, but why should I?
>I prefer to just explain that it's a question that won't help you in the slightest. I'm not going to illustrate something that will, or give you any examples.
>Just do it. The important thing is, not in front of me.
Author, you could vastly improve your blog post by actually doing the teaching instead of sending the student off.
This is like me criticizing how classes are taught, without offering my version or showing how they should be taught. Come on.
I'm afraid this post is completely without any value. It's an outline for the post that the author should write, when the author figures out how to teach monads (which don't exist in all languages) properly. Building up from several usage cases, per the author's outline.
The only problem with the outline is that it's notes to self on how to teach monads well. Well, go ahead then. Put your money where your mouth is and teach people who have never used a monad how to use a monad. Which is why they're asking.
You may not even need the monad instance for IO -- for example, you might just use its functor instance.
I played around with these as a mini demonstration of using IO in Haskell without any mention of monads: https://gist.github.com/jameshfisher/1d735b5267e8f848b280
Likewise, if you've never actually worked with monads the high level explanations aren't terribly useful.
Take as an example the following paragraph from Wikipedia:
> The essence of the Mediator Pattern is to "define an object that encapsulates how a set of objects interact". It promotes loose coupling by keeping objects from referring to each other explicitly, and it allows their interaction to be varied independently. Client classes can use the mediator to send messages to other clients, and can receive messages from other clients via an event on the mediator class.
I have no idea what that means and how and when I apply it in practise. It's just a bunch of abstract mumbo-jumbo, like an explanation of "what a monad is" will be.
So I still hold that the abstract description comes after you learn how to use the thing, not before it.
I think the main problem is that most programmers are terrible at explaining things, and should just stick to code examples, because they're usually a lot easier for other programmers to understand.
I also couldn't find a post or a video that would explain what monads are in cateogy theory.
fmap (*3) (Just 12) === Just 36
When the type is some sort of computation type (IO, Promise, STM, Parser, unwrapped Reader), the functor interface gives you a function that will take a function and compose it with the computation. In other words, the result of the computation will be passed through your specified function before it is finally returned. Example: fmap (+5) (getPromise age)
-- promise age is filled with 43 and
-- the fmap call will return 48A functor in Category Theory has two parts - a map of the objects and a map of the arrows. In Haskell, when you create a Functor instance, you are saying "this type constructor is the map for objects; here's how you map the arrows".
It's typically not the best place to start, but since you asked - a monad, in category theory, is a functor plus two natural transformations. In Haskell, the functor is the type constructor plus fmap from the Functor instance. The natural transformations are return (eta, in the math) and join (mu). Haskell programmers have historically found it more useful to talk about bind than join, but in the presence of fmap you can implement either from the other, so there's not much theoretical difference:
join m = bind m id
bind m f = join (fmap f m)No results found for "abbott and costello explain monads".
The hardest thing to get is that Monads aren't quite as "tangible" (not sure of a better word) as concepts like variable, object, property, instance, function, method. They are essentially relational and require something of a mental leap akin to coming to grips with how JavaScript's event loop is bound up in the control flow of your code, which otherwise proceeds from top to bottom of a .js file; or the rules governing closures and asynchronous function evaluation in this or that language.
The following is reprised from one of my HN comments in 2013.
-------
Monads are programming patterns which relate a set of values to a set of of functions – that's pretty much it! For any monad X, we can say that a function is monadic if it returns a value in the X Monad. The set of values are precisely those such that the following three Monad Laws[1] hold:
[ Using JavaScript syntax, they can be approximated as... ]
Left Identity
mBind( mReturn(a), f ) == f(a);
// => true
Right Identity mBind( mReturn(a), mReturn ) == mReturn(a);
// => true
Associativity mBind( mBind( mReturn(a), f ), g ) == mBind( mReturn(a),
function(a) {
return mBind( f(a), g );
} );
// => true
Above, `a` is (basically) any value, while `f` and `g` are any monadic functions for the same Monad. The definitions of `mBind` and `mReturn` will vary depending on the Monad, but the same laws (and sometimes additional properties) hold for each group of things taken as a whole – the monadic values, monadic functions, and the `mBind` and `mReturn` pair for those values and functions.As you can see, there is nothing special that requires a statically typed language. That being said, if your language is statically typed, and even more so if its type system has advanced capabilities (e.g. Haskell's type system), then the relationships between the monadic values and functions can be leveraged to do a number of useful things, e.g. catching a host of bugs at compile time (though that's true regardless of Monads).
If your language is dynamically typed, then you won't get those extra benefits, but you can still take advantage of the fact that Monads can abstract away a great deal of plumbing between various pieces of your program.
Sometimes the Monad patterns will appear in a language under another name, or will be used "under the hood" to implement a particular API. Clojure/Script's `let` for example is essentially the Identity Monad; and its `for` is very much akin to the List Monad (the same is true for list comprehensions in other languages). The core.async library involves an inspiring application of the State Monad pattern[2].
[1] http://en.wikipedia.org/wiki/Monad_(functional_programming)#...
[2] https://github.com/clojure/core.async/blob/master/src/main/c...
[&] https://github.com/clojure/core.async/blob/master/src/main/c...
> For any monad X, we can say that a function is monadic if it returns a value in the X Monad.
You're defining a monad by using itself in the definition! A definition is recursive if it recurses.
I sort of understand the three laws after that, but it's like someone asking "what are operations on numbers" and getting the answer "operation is any operation that's associative, commutative, etc". It does nothing to explain monads to me, it just tells me that a monad is any thing that obeys three things. That information is completely useless to me.
The parent is not defining a monad with that sentence, he is defining what a monadic function is given that you have something that behaves like a monad
> I sort of understand the three laws after that, but it's like someone asking "what are operations on numbers" and getting the answer "operation is any operation that's associative, commutative, etc". It does nothing to explain monads to me, it just tells me that a monad is any thing that obeys three things. That information is completely useless to me.
The thing is that there is not much more to a monad than those three laws and the two functions(return and bind/join).
Nonads are remarkable because lots of things happen to behave like monads(i.e have return and bind defined in a way that follows those operations). This includes interpreters, actions with side affects, non deterministic computations, computations with the possibility of failure and many other things.
Monads are useful because they let you write code that is reusable across all monads and not just the one you happen to be coding for. If you look at code that is written like this, after enough experience you will get a vague idea of what it does, but its actual function will almost completely differ based on what kind of monad you use it for. This gives you a great amount of flexibility and refactorability as you can tweak and extent monads or create entirely new monads while still having this great mass of reusable code already written for you to use.
Like the OP says, a monad is not some tangible concept like an object or a function. It is a concept that groups other concepts together.
To learn about monads, you have to look at specific examples like the List monad, or the State monad or the IO monad. But there is no general explanation of a monad any more tangible than what the parent said.
But I have no idea what a monad is, so it's all equivalent to "a blorx function is a function that returns a value in the blarx blorx". He never explained that a monad is different from a function, or that a monad is something that has values, or that you can return them, or any of the parts that make up that sentence.
> To learn about monads, you have to look at specific examples like the List monad, or the State monad or the IO monad. But there is no general explanation of a monad any more tangible than what the parent said.
I have a feeling that that's exactly what someone who attempts to explain what monads are should talk about. If they're a general concept, like patterns (the concept of patterns in general, not specific patterns), it is probably clearer to show how specific examples work and then how they relate to each other, so someone who doesn't know anything about them can grasp their significance.
Anyway it's like the word 'if' or 'except'. You just need to know about the syntax or any rules. Type "define monad" into Google if you don't know this super-basic word. (Personally, I would have thought most of us learned it when we were 3 or 4 and learning the numbers or the alphabet song). Anyway watch:
http://google.com/search?q=define%20monad
it clearly tells you,
>Monad: a single unit; the number one.
What could be simpler?
So we can simply understand the OP's definition:
> For any monad X, we can say that a function is monadic if it returns a value in the X Monad.
plainly:
> For any X that is equal to the number one, we can say that a function for it is equivalent to the number one if it returns a value that is the number one.
in other words, the definition of a monad is just a function that returns 1 in all cases. This definition is super-simple. I have no idea why you object.
here are some examples of monads written in C:
int raise_to_zero(int x){ return 1; }
this is a monad to raise a number to 0. Here is another one:
int multiply_by_zero_and_add_one(int x){ return 1; }
this is a monad for multiplying by zero and adding one.
yet another would be:
int divide_by_self(int x){ return 1; }
You get the idea. Likewise there are monads for all sorts of times that you need a function to return one in all cases.
It's really not hard. There's nothing circular or unusual about the OP's definition. He's just using plain everyday words we've all known since second grade, in their usual meanings. I'm at a loss why you would have trouble with this.
NOTE: I'm certainly not an expert, so if I've left anything out, anyone should feel free to correct me!
(pssst - this might be the only way of getting anything out of these folks.)
Monadic functions have the type (a -> M b) return has the type (a -> M a), so injecting a value into a monad bind has the type (M a -> (a -> M b) -> M b), or without currying, (M a, (a -> M b)) -> M b, so that given a monadic value (M a) and a monadic function (a -> M b), you get a result of type M b.