
Haskell Concepts in One Sentence - crystalPalace
https://torchhound.github.io/posts/haskellOneSentence.html
======
scottmsul
A monad is any data structure which implements bind. Bind is a higher-order
function with two parameters - one is the data structure to be transformed,
the other is a function which maps over elements in the data structure.
However, unlike a normal map, each result of "bind" sits in its own version of
the original data structure, which then have to be combined back into a single
data structure. The way in which the data structures are combined is what
makes each monad different.

For example, List is a monad. Suppose we had a List of Ints, such as [5,3,4].
If we were to run bind over this list, we would need a function that takes an
Int and returns a List of something. We could use "show", the function which
converts Ints to Strings (a String is technically a List of Char. Since this
is a List, we're good). If we call bind using [5,3,4] and show, we get
["5","3","4"] which are then combined to "534".

We can check with the interpreter (>>= is bind):

Prelude> [5,3,4] >>= show

"534"

~~~
jnordwick
> each result of "bind" sits in its own version of the original data
> structure, which then have to be combined back into a single data structure

That doesn't make sense to me. Let's say I have the list [5,3,4], to me that
means each application returns a three element list [f(5),x,x], [x,f(3),x],
and [x,x,f(4)] then the bind function takes these lists and turns them into
[f(5),f(3),f(4)].

What makes this function a monad?

~~~
gizmo686
In this case "data structure" refers to List, not a specific size or type of
list.

For example, suppose you have a list of ints, and want to bind a function,
show. We have types:

    
    
      [5,3,4] :: List Int
      show :: Int -> List Char
    

That is to say, [5,3,4] is a list of ints, and show is a function that takes
an int and returns a list of characters.

In this case, we would have

    
    
      [5,3,4] >>= show
      f(5) ++ f(3) ++ f(4)
      ['5'] ++ ['3'] ++ ['4']
      ['5','3','4']
    

where "++" is list concatenation. The idea here is that when we apply show, we
get back 3 different Lists, and want to combine them into a single list.

~~~
jnordwick
So bind is flat map in other languages? If join is a function that take a list
and appends its elements together join ( [[1], [2], [3]] ) -> [1,2,3]

then bind is join(map(f, x))?

bind just seems like a terrible name.

For some reason Haskell users try to make things sounds as academic as
possible.

~~~
gizmo686
>For some reason Haskell users try to make things sounds as academic as
possible.

Probably because Haskell ended up being the language for academics. If you
want to do programming language research in an ML-type language use Haskell.
If you want to make a product, use OCaml. Not entirely true, but pretty close.

>So bind is flat map in other languages.

In the case of a List, yes, but there are other datastructures that implement
Monad. This type of thing happens a fair amount in Haskell. It is not that
uncommon to see code like:

    
    
        instance Monad List where
            (>>=) = flatMap
    

That is to say, the implementation of the interface is just another function
that has a more domain specific name.

There are other monads with a bind that cannot be understood as flatMap.

For example, the Maybe datatype is Haskell's version of Optional. For example,
if a variable is of type `Maybe t`, it either contains a single value of type
_t_ , or no value. It is common to use Maybe without using it as a monad.
However, Maybe does implement the Monad interface. In this case, bind is
defined as follows:

    
    
        x.bind(f) =
          if (x.hasValue()) then { return Just(f(x.value)) }
          else { return Nothing() }
    

where Just and Nothing are two constructors of Maybe. If we view 'no value' as
analogous to null, then this bind function is null propogation.

~~~
Forlien
I feel a bit dumb asking this, but your explanation doesn't make it clear to
me why you can't think of a bind on Maybe as a flatMap on a List with 0
(Nothing) or 1 (Just) elements. Could you elaborate further on how thinking of
a bind on Maybe as null propagation eliminates it also being interpreted as a
flatMap on a restricted-size list?

~~~
fmap
You're right, maybe is equivalent to the type of lists with at most one
element. There are however monad instances which are genuinely different.

For example the state monad is defined as

    
    
      F(X) = S -> S*X
    

I.e., a value of type F(X) is a state transformer which takes a state argument
of type S and produces the new state and a value of type X. In this case, bind
is sequencing of state transformers.

Using the state monad you can write code that looks like it uses a global
variable of type S, while being completely pure which makes testing and
refactoring easier, and of course doesn't pollute the rest of the program.

------
jnordwick
My general problem with Haskell articles and such: they are written as if you
already understand Haskell. They make total sense if you know the language,
but if you are trying to learn are mostly useless if not more confusing. Or
even worse, they devolve into dense academic prose even when writing
introductory articles.

Sometimes they even use Haskell as if you already know it to try to explain
it.

I'm still looking for a basic article that describes monads well. My first few
languages were all functional too, so that isn't the problem. I even still use
APL derivatives.

~~~
ycmbntrthrwaway
Read this:
[http://learnyouahaskell.com/chapters](http://learnyouahaskell.com/chapters)

Just don't skip chapters and read from the beginning to the end.

~~~
alok-g
You advice here may be good; am not questioning that. However, question does
come why can't there be a shorter explanation for people who already know
programming. Most people are unable to explain it well, or at all, leading me
towards a belief that they don't get it themselves as yet.

~~~
ycmbntrthrwaway
You can explain what a monad, for example, is, in one sentence, but it is
useless if you don't show how it is used.

Similarly, you may know what eigenvector, or derivative function, is, but
without practice you can't understand why you may want it.

~~~
alok-g
I'm not looking for a single sentence explanation or definition. I'm willing
to read more, and the structure you suggest of showing precisely worded
definitions along with positive and negative examples would be great! However,
I would not want to start with reading how to install a compiler, how to add
two numbers in Haskell, etc.

I have similar issues elsewhere when people start with hello worlds and
getting started in introductions to projects and programming languages without
spending enough time on what the thing is about.

------
oblio
I'm still kind of having problems with monads. Funnily enough, I recently
found an article explaining what monoids are:
[https://fsharpforfunandprofit.com/posts/monoids-without-
tear...](https://fsharpforfunandprofit.com/posts/monoids-without-tears/)

    
    
        You start with a bunch of things, and some way of combining them two at a time.
    
        Rule 1 (Closure): The result of combining two things is always another one of the things.
    
        Rule 2 (Associativity): When combining more than two things, which pairwise combination you do first doesn't matter.
    
        Rule 3 (Identity element): There is a special thing called "zero" such that when you combine any thing with "zero" you get the original thing back.
    
    
        With these rules in place, we can come back to the definition of a monoid. A "monoid" is just a system that obeys all three rules. Simple!
    

Long explanation overall in the article, but based on 6th grade math. I
understood it, and it stuck. Could someone extend the monad explanation from
here? Maybe I'll finally get it :)

~~~
cynicalkane
Start with a functor--a parameterized type with fmap. Maybe t, Either e t,
[t], IO t, State s t, and so on.

Consider a monad m and a function, a -> m b. Frequently you want to feed
another monadic value, m a, into that function.

A monad gives you a function, >>=, that lets you take m a and feed it into a
-> m b.

So any function that does IO, that looks like a -> IO b, you can take an IO a
and plug it into a -> IO b. Any function that manipulates a state, you can
take State a and plug it into a -> State b. This is the heart of a monad:
gluing monadic functions together.

The meaning of >>= depends on the monad you're in. You also need return :: a
-> m a, which can take a thing and put it in a monadic value.

There are monad laws also. A lot of times there's several ways to manipulate
monads to do something, and the laws are needed to make sure they're all
equivalent. For everyday monad use the laws aren't terribly important to
remember, and GHC's linter will helpfully point out when you can use them.

That's my attempt at a short explanation. The "monad tutorial problem" has
been weighing on my mind. The only way I ever understood monads was by reading
and rereading the definition and examples. Tutorials never taught me anything.

~~~
slmyers
I'm still slightly confused. The author suggests that a monad is composed of 3
functions. It seems to me you've shown 2 of these functions.

a -> m b

>>=

What is the third function? Did I misunderstand you?

~~~
gizmo686
The author is mistaken. There are only two functions necessary for a monad:
>>= and return

Also, the type of return is `a -> m a`. The type you cite `a -> m b` is a
parameter to >>= (which has type `m a -> (a -> m b) -> m b.

The author might be refering to a quirk of the Haskell monad interface, which
has to additional functions:

">>" which can be easily defined in terms of >>=. I assume this is part of the
interface so users can override it with a more efficient implementation, but
every implementation I have seen just uses the default one.

"fail" which is an error handler. This is being depreciated as a function of
Monads, and moved into its own MonadFail typeclass. This also has a default
implementation that just throws an exception.

~~~
rdnetto
I suspect the third function is the one for running the monad. It's different
for each one, so it's not part of the type class, but you do need it to use a
given monad. (Except IO, though even it has unsafePerformIO)

~~~
gizmo686
What is the function for running Maybe, or List?

------
aetherspawn
Monads are not complex. A monad is a box. Any monad has two functions (plus
others, imagine this is a minimal interface): bind and return.

You can put anything in the box. It's TARDIS-like.

`return` replaces the thing that was in the box.

`bind` replaces the box.

Most monads have a number of functions that can only be executed over boxes.
This is because the boxes have special metadata (for example, someone has been
scribbling state underneath the box). The 'get' function from the State monad
just tells you to read the gibberish on the box instead of unpacking the box.
The 'set' function scribbles more stuff on the bottom of the box.

Useful monads then provide a function to put things into the box, work with
the box and then throw the box away (or inspect it by itself). These are the
functions called 'runWhatever' for example 'runState', which lets you put an
apple in the box, put a shipping label onto the box and then eventually
separate the apple and the shipping label into each hand, throwing the box in
the bin.

You can put anything in a box. Even more boxes. And when you're inside the
box, you can't really tell how deep you are. If you're in the bottom box you
can't actually see that you're in 20 layers of boxes, and this is why Monads
are so powerful for creating libraries and frameworks.

~~~
bogomipz
Thanks for your explanation. I confused as to why so much discussion and blog
posts surround the topic of monads as if they were very difficult to
understand then?

I would be curious to get your thoughts.

Also I didn't understand the word TARDIS-like.

~~~
aetherspawn
The TARDIS is a box from doctor who that is bigger on the inside (holds a
small pocket universe inside). You can put anything inside the TARDIS.

My explanation of Monads approaches them from a practical angle rather than a
theoretical angle. It won't help you make your own, but it will help you
appreciate why people make them.

~~~
bogomipz
I see, thanks for the explanation. That's a good analogy. Cheers.

------
mpfundstein
IMO the most accessible resource for learning functional concepts like
Functors, Applicatives and Monads is the free online book:
[https://github.com/MostlyAdequate/mostly-adequate-
guide](https://github.com/MostlyAdequate/mostly-adequate-guide)

It uses Javascript to explain everything from scratch. Pure-functions,
currying, composition, functors, monads, applicatives and so on.

Its free, so check it out. Reading it and understanding the concepts
completely changed my whole coding style in the last couple of month. I hope
functional javascript becomes more mainstream and we will soon call this stuff
'standard'. Its just too convenient to stack a Future on top of a Reader and
get dependency injection + async function handeling without any boilerplate
code.

P.S. Since ES6, javascript is wonderful. Functional code often really looks
like lisp. Pity that we don't have macros (yet, and actually there is a way
(sweet.js).

P.P.S. If DrBoolean got you hooked. You might want to check Ramda and fantasy-
land. The former is a more functional minded underscore/lodash, the latter a
specification (and community) for algebraic data structures in javascript to
which a lot of new libraries adhere to.

~~~
lolive
Your comment made me read this book. This book changed my life. A biiiillion
thanks !!!!

------
LeanderK
To everyone new to haskell and confused: Don't judge haskell based on these
definitions. They appear strange and crazy, but when you actually do stuff
most of them turn out to be quite intuitive.

My advice is to ignore these things. Don't read a million monad tutorials.
Just play around and code something, you don't have to understand the monad-
definition before you can use the do-notation. Try to ignore them. After a
while you get an intuition and then the definitions will make sense.

~~~
AsyncAwait
I've found parser combinators to be a fun and useful way to play around with
monads, since it's pretty easy to implement your own monads this way, and what
better way to understand something, than to actually make it?

~~~
LeanderK
i agree! They are also surprisingly useful and not incomprehensible like
Regex.

------
rawicki
I see traces of OP getting to understand the joke "A monad is just a monoid in
the category of endofunctors, what's the problem?" :)

------
Cybiote
This is a good start and might be useful to other beginners. From the vantage
point of someone who already knows what the words mean, I can fill in the gaps
in your definitions but unfortunately, a beginner might not be so able.

Here are some suggestions on how you might close some of those gaps a bit (I
think allowing yourself to go over a sentence here and there should be ok).

You use fmap more than once without having defined it.

Currying: You need to define partial application.

Map and filter, I'd use collection instead of list. There is more nuance but
that is good enough at this level.

Morphisms generalize the concept of function. They can be thought of as
capturing structure (such as a set equipped with + and 0) preserving maps
(which is something analogies try to do).

lazy evaluation could do with mentioning thunk, then you'd have to define what
a thunk is, of course.

Fold: Folds are a lot more interesting and it's not clear what you mean by
your given definition. I suggest defining it in terms of structural recursion.

Category: It's worth defining what objects mean to a category. As well,
explicitly mentioning the laws of identity, composition and associativity
rather than just the nebulous wording of configuration would be beneficial.

Functor: A more useful foundation is in thinking of functors as morphisms
between categories.

Types: There is much more to types than this. Wrong in the correct direction
is to think of types in terms of sets. Better yet, as propositions.

Type Classes: Since you mention parametric polymorphism, you should also
mention ad-hoc polymorphism and how type classes and interfaces are examples.

algebraic data types: There's a lot more to algebraic data types than this.
After defining sum types and product types elsewhere, you can talk about why
such types are called algebraic.

parametric polymorphism: what is a type variable?

monoid: Moniods also need an identity element, and giving examples is always
useful: natural numbers: +,0 or strings: +,"". One reason monoids are of
special interest to computing is because they possess associativity, which is
useful when parallelizing.

------
iamwil
It'd help beginners if there was a sentence explaining what fmap is.

~~~
chrisdone
In Haskell and PureScript, `fmap` is a method in the `Functor` class, which is
defined by

    
    
       class Functor f where
    
         fmap :: (a -> b) -> f a -> f b
    

for which instances should satisfy `fmap id = id` (and you get `fmap (g . f) =
fmap g . fmap f` for free). If you can find a type for which you can implement
`fmap` and satisfy the laws, then you have an instance of `Functor`.

That's the precise and short definition. It assumes the following knowledge:

0\. How partial application works and the . works.

1\. How Haskell's type-classes work (`Functor`).

2\. How Haskell's methods work (`fmap`).

3\. How Haskell's higher-kinded types work (the `f`).

So good luck explaining `fmap` in one sentence unless you already know Haskell
and understand its type system to a confident degree, which depending on your
background can take weeks to months.

~~~
iamwil
There's often no need to explain everything in detail to get the gist.

------
init0
Jargon from the functional programming world in simple terms!
[http://git.io/fp-jargons](http://git.io/fp-jargons)

------
bonoetmalo
We should probably add a sentence about not using fixed margins that will make
the text body 1/5th the width of my screen.

~~~
crystalPalace
My apologies, I nixed the hardcoded 100px margins and used percentages
instead.

------
edem
This is all useless for someone without haskell experience.

------
hota_mazi
> A monad is composed of three functions

Actually just two (bind and return). And three laws which are typically not
captured in the type system and which must therefore be tested separately.

------
burticlies
One simplistic but useful analogy I've found is that monads are a way to
control program flow with functions. A monad is to functional programming what
if/else is to imperative.

It may not cover all the nitty gritty about what is and isn't a monad. But it
gets you a long way to understanding why you might use them.

------
strictfp
A monad is a wrapper type designed to alter the semantics of chains of
operations performed on its wrapped values.

------
babbeloski
Question to JS people using Redux. Are the middlewares used to control side
effects in actions considered monads? The action returns a description of the
side effect, and the middleware handles the actual doing, leaving the
programmer to focus on the pure aspects.

------
ncphillips
These sentences are nice, but I feel like more definitions and some re-
ordering could make the document as a whole more meaningful.

For example, Lift is defined way before Functor, and fmap is never defined so
I had no idea what Lift was about despite that nice concise sentence.

------
csneeky
What an excellent distillation!

It isn't uncommon to see someone w̶i̶t̶h̶ ̶a̶ ̶f̶r̶a̶g̶i̶l̶e̶ ̶e̶g̶o̶ explain
this stuff in a way that is needlessly complex and full of jargon that scares
folks off.

Thanks for the great work here. We need more of this kind of thing in the FP
world!

------
mbfg
There is an adage that if you see a lot of advertising for a medicine (think
hair regrowth formulas, or pills of reflux disease) you know that none of them
are any good.

This page makes me wonder about monads in the same way.

~~~
marcosdumay
Do you think any of those is paid in any way?

------
jpt4
Article appears to be in flux; definition of lazy evaluation changed.

~~~
crystalPalace
My change is reflected in my use of "Last Updated 3/25/2017" and in my commit
message. Thank you for ensuring transparency.

------
dmead
whats the third function for a monad? bind return and...?

~~~
gizmo686
Haskell does have "fail" as part of the Monad typeclass. But it is being
depreciated and moved into the MonadFail class.

Haskell's Monad also has >> and >>= both defined as part of the typeclass
itself; instead of making >> a normal function. The typeclass does provide a
default implementation of >> in terms of >>=.

But you are correct. In general all you need for a monad is bind and return.

[http://hackage.haskell.org/package/base-4.9.1.0/docs/Prelude...](http://hackage.haskell.org/package/base-4.9.1.0/docs/Prelude.html#t:Monad)

~~~
platz
That's all you need to make the compiler happy, but it's not a monad without
satisfying the laws too

------
leshow
I'd modify the monoid line to include associativity and identity:

A monoid is a a type with an associative function and an identity function

------
a_imho
The problem when starting out with Haskell is that you can't google type
errors.

------
bogomipz
This is brilliant, thanks for sharing.

------
nickpsecurity
Hmm. They certainly have a naming and explanation problem in Haskell land.
Some impressions from a few of these better explanations.

"A monad is composed of three functions and encodes control flow which allows
pure functions to be strung together."

Gibberish compared to claim that monads just execute functions in a specified
order. Aka an imperative function or procedure by one definition I've seen a
lot. Of course, that monad definition might be wrong, too.

"A recursive function is a function that calls itself inside its own
definition."

That's a recursive definition lol. Must have been a joke.

"A monad transformer allows you to stack more than one monad for use in a
function."

We've had composition of procedures for a long time. Perhaps Haskell could've
called it a MonadComposer?

"Lift is an operation on a functor that uses fmap to operate on the data
contained in the functor."

fmap-apply() or something like that?

"Optics(lens and prisms) allow you to get and set data in a data type."

Getters and setters. My early OOP/C++ books are finally more intuitive than
something.

"Map applies a function to every element of a list."

foreach(function(), list)

"A predicate is a function that returns true or false."

A boolean function.

"Filter applies a predicate to a list and returns only elements which return
true."

Syntactic sugar for a foreach(function, list()) where the function on each
member is an If (Conditional) is TRUE Then AddElementToNewListThatsReturned().
Yeah, even the description of imperative version is getting long. This might
be a productivity boost.

"A morphism is a transformation from any object to any other object."

A cast from one object to another? Or one with an actual conversion function
and/or check? The functional name seems more accurate, though.

"Algebraic data types are a method to describe the structure of types."

Ahh, they're just structs. Wait, what is a type exactly? And therefore what is
an abstract... oh darn...

"Free monads allow the transformation of functors to monads."

A functor is an object that can be fmaped over. We covered map. Maybe the
same. A monad is either an ordering of functions or something composed of
three functions and encodes control flow composed of pure functions. Free
monads are apparently an unknown thing that can transform objects that can be
fmaped over into something composed of three functions with encoded control
flow of composed, pure functions. I heard a lot of good Masters and Ph.D.
proposals before this one. This is good, though. Especially quantifying the
unknown aspects with a lot of NSF-funded R&D.

"A lambda is an unnamed function."

"Types are an inherent characteristic of every Haskell expression."

"Currying uses partial application to return a function until all arguments
are filled."

"A category is a collection of objects, morphisms, and the configuration of
the morphisms."

Ok, I just have fun with that one. Author did good on a lot of them. I'm just
going to leave these here as quotes to add to Free Monads in... The Advanced
Course: Haskell in Two or More Sentences. They provide anywhere from no
information at all to the uninitiated to extra confusion inspiring taking or
avoiding Haskell courses. :)

~~~
Tarean
Pure functional programming means that everything a function does has to be
part of the return type. That means you often get functions like

    
    
        a -> Maybe b
    

Instead of throwing an exception or returning null to make the possible
failure part of the return type. Chaining failable functions would be
incredibly annoying, though:

    
    
        let a = tryRead
        if isNothing a
        then Nothing
        else
          let b = tryParse (unwrap a)
          if isNothing b...
    
    

In imperative code you could flatten this with early returns but that still is
a common pattern, so lets abstract this!

    
    
        tryRead >>= tryParse >>= tryProcess
    

The magic sauce is in the >>= combinator, pronounced bind or andThen. It
returns Nothing instantly if it receives Nothing, otherwise it unwraps it and
calls the next function.

There are a lot of other things that we could encode in a generic type tacked
onto the return value and which we want to chain like this.

Futures in async io, passing around config/state instead of having global
variables or the order in which ffi/io is run (the use case you have heard of
most) would be a couple examples. You can even abuse bind to add things like
implicit backtracking on failure!

So the really cool thing about monads is that you can add new behavior to
functions without implementation details leaking during composition!

The cool thing about lenses is that they enable getters/setters for things
like entries in a hashmap or all string fields in a struct at once.

~~~
nickpsecurity
"So the really cool thing about monads is that you can add new behavior to
functions without implementation details leaking during composition!

The cool thing about lenses is that they enable getters/setters for things
like entries in a hashmap or all string fields in a struct at once."

Good reply. Yeah, I definitely see these as beneficial.

