
A Gentle Intro to Monads … Maybe? - flippyhead
http://sean.voisen.org/blog/2013/10/intro-monads-maybe/
======
jerf
This does not appear to implement a monadic computation. A monadic computation
can examine intermediate steps of the computation and perform flow control
decisions, i.e. in Haskell:

    
    
        showFlowControl :: Person -> Maybe County
        showFlowControl p = do
            country <- personCountry p
            case country of
                USA -> do
                    state <- state country
                    county state
                SomethingElse -> do
                    province <- province country
                    provCounty province
                _ -> Nothing
    

(The implied data structure is a bit bizarre, but, bear with me.)

Unless I am misreading the code, this is the rather frequent misunderstanding
that monads are just fancy chained method calls, which does not suffice to
capture the monadic behavior. Note merely trying to stuff "if" statements into
the calls won't be sufficient, because you must actually _affect the chain
that is called_ ; either you call "state" or you call "providence" but you
must decide that "in" the monadic computation, not in a mere method chaining.

Mere method chaining is not monadic. There is, I believe, no clever way to
implement monadic computations in Javascript without _nested_ functions; every
layer of the monadic computation _nests_ , and in most languages this can not
be hidden in any practical way. This is one of the major reasons monadic
computations are impractical in most languages.

~~~
dllthomas
Fancy chained method calls are equivalent to do notation without any binds,
which only needs Applicative. Monad is sufficient but not necessary.

That said, this _does_ appear to be a monad - they implemented bind correctly.

Haskell:

    
    
        instance  Monad Maybe  where
            Nothing  >>= _      = Nothing
            (Just x) >>= k      = k x
    

From the article:

    
    
            var Nothing = {
                bind: function(fn) { 
                    return this; 
                }
            };
        
            var Something = function(value) { 
                return {
                    bind: function(fn) { 
                        return Maybe(fn.call(this, value));
                    }
                };
            };
    

It doesn't really _use_ it right, for the most part, though (... I think; I
only skimmed).

~~~
jerf
I think bind is essentially correct too, but the failure to use it properly
tends to suggest a level of understanding too small to be writing Yet Another
Monad Tutorial. I've seen real JS monads, and I believe they are irretrievably
ugly to use, with the need for nested functions.

------
jasallen
So, I don't get all the pain. There are a lot of 'rules' around monads, but
conceptually they are widgets in a workflow.

In imperative programming you say what you want to do and do it at the same
time.

With monads, you assemble a chain, just like dropping boxes on a workflow UI.
Just like a workflow, you have 'defined' what to do, but not done anything
with it yet. When you give it input, the chain performs the transforms you
have defined for it, and you can pull out the result.

Again, not a 'technical definition' but this paints a picture in people's
heads that they can appreciate and follow it up with details.

For serious learning, I recommend Eric Lipperts blog post on the subject:
[http://ericlippert.com/category/monads/](http://ericlippert.com/category/monads/)

------
mbseid
I made a port of some Scala Monads to Javascript. Mostly, Option and Either.
Makes for some really nice, and you won't find yourself doing (typeof foobar
=== "undefined").

[https://github.com/mbseid/Monad.js](https://github.com/mbseid/Monad.js)

------
rogerallen
Suggestion for the author. Reformat the code of your translated example. I
truly found it impenetrable until I formatted it more like idiomatic d3.js
code. With this reformatting, I'll buy that it is less annoying and tedious
than the original.

    
    
        console.log(
          Maybe(person)
            .bind(function(p) { return p["address"]; })
            .bind(function(a) { return a["state"]; })
            .maybe("State unknown", function(s) { return s; })
        );
    

And then I realized that _d3.js code is monads!_ (shout it like Charlton
Heston in Soylent Green)

~~~
dllthomas
I'm not sure this is actually using the fact that maybe is monadic - I think
this much can be done with applicative functors. In order to really be
monadic, you'd need to run the next bind inside the function passed to the
previous bind.

------
Mithaldu
This misses the more simple explanation of Monads:

    
    
        They're functions provided by the language core,
        that cannot be implemented in the language itself,
        because the language rules forbid it.
    

This should be the first thing any of these introductions explain. Afterwards
they can spend however long they like explaining all the rules for which
Monads are solutions and how they get around them, safe in the knowledge that
the reader will at least know why monads exist and why people are going to all
these efforts.

~~~
FreezerburnV
Can you give an example of a language rule which a Monad might implement? I
sort of understand what you mean, but an example would help me (and maybe
others?) form a more concrete understanding.

And if at all possible, don't use Haskell being unable to mutate state as an
example. Maybe an example for Javascript or Python?

~~~
Mithaldu
In Haskell some big rules you get around are:

1\. Functional purity must be maintained for all code. This means for example
that no side effects (IO) may happen. Thus some monads exist for the simple
purpose of doing IO.

2\. As you mentioned, state may not be mutated. To circumvent that there's a
monad that simply marks a code block as "variables of this type may be changed
in here, as long as they don't get out of this scope".

3\. I only know about this vaguely, but as i understand it Haskell is strictly
typed. This makes some things inconvenient, so Maybe allows some loose typing.

I can't give examples in JS, but i actually got one for python: Decorators. In
Python you cannot implement a function with this specification:

    
    
        It takes exactly these inputs in this order:
          1) a function object,
          2) a function name,
          3) a multiline anonymous function.
        It calls the function passed as the first parameter,
        with the third parameter as its parameter.
        It takes the result, which is expected to be a function,
        and installs it in its calling scope as a new function,
        with the name passed in the second parameter.
    

Since this is not possible to implement in pure python, decorators were
implemented in the core. I'm not 100% sure, but i think they actually do
qualify as monads.

~~~
tel
1\. IO doesn't have to be a monad, it simply was designed that way because the
monad interface is so nice. In older (very functional) versions of Haskell
this wasn't the case.

2\. That's honestly not a bad description of the State monad spoken using
procedural vocabular, but it is _very_ far away from an accurate
representation. At the very least it's worth noting that this isn't a
syntactic thing—all of the elements are first-class.

3\. Maybe is still strictly typed. It causes the possibility of null to be
represented at the type level so that nobody ever accidentally forgets to
check it. I _never_ get null errors in Haskell.

Finally, decorators are Functors perhaps, if you strain to look at them that
way, but not at all monads.

~~~
Mithaldu
> Finally, decorators are Functors perhaps, if you strain to look at them that
> way, but not at all monads.

You can't say such a thing and then run away without saying why not. How is
anyone supposed to learn about this if nobody explains the why? :)

Edit:

> 3\. Maybe is still strictly typed. It causes the possibility of null to be
> represented at the type level so that nobody ever accidentally forgets to
> check it. I never get null errors in Haskell.

Let me reword point 3. Haskell is strict about types in that it asks you to do
a lot of checking. Using Maybe you can make Haskell behave like a loose
language that doesn't require any checking from you.

~~~
tel
Python decorators are basically as follows

    
    
        @f
        def g(args) body
    

translates as

    
    
        g := f(fun(args) body)
    

If my syntax makes sufficient sense (g := a translates as "assign a to g").
That means that decoration is nothing much more than function composition
which forms a very particular functor. That same Functor also provides a
monad, but continuing to work this example until that's clear is so far from
obvious that I think it'd only serve to mislead.

~~~
Mithaldu
If it isn't a monad, but provides one, then this seems to be the perfect
example to explain on, since decorators are understood and monads are
something smaller than decorators and as such should be able to be explained
by reducing the explanation of decorators.

Also do keep in mind that i didn't say decorators were a monad in any
language, just in python, because they cause a curious side effect that is
otherwise only attainable with much self-repeating and hard-to-read syntax.

~~~
tel
Yes. Decorators do not provide a monad at all, not even in Python. The very
dim relation between the two is academic at best and completely irrelevant at
worst.

~~~
Mithaldu
Yes what?

Also, you wrote:

> decoration [...] forms a [...] functor. That [...] Functor also provides a
> monad

That is entirely at odds with the statement:

> Decorators do not provide a monad at all

Frankly, at this point i'm strongly considering the possibility that you're
just trolling me.

~~~
tel
I'm not trolling, we're just talking around one another. There are a
significant number of concepts that aren't easily explained in plain english
required to get at the heart of "what is a monad?". Even that question itself
is already making an interesting choice of definition and set of questions
that can be confusing unless analyzed carefully (in particular "Monad" as a
noun can mean something very different from monad as an adjective and both
meanings are frequently used in descriptions of "what monads are").

I'm attempting to be strongly consistent in everything I'm saying, but it's
not necessarily possible to both do that and keep speaking simply.

The why of monads is that they're a very nice API or Interface that allows you
to write easily analyzed and easily refactored programs. Most of the other
descriptions are the why of a _particular_ type which happens to instantiate
the API.

~~~
Mithaldu
That sounds nice and all, but i still don't know why you contradicted
yourself.

~~~
tel
Okay, I'll explain it. Apologies for the apparent contradiction—I'm not trying
to move the goal posts, just trying to avoid going into the weeds.

As I said, Python decorators are essentially just a syntax for function
composition.

    
    
        @deco
        def g(args):           g := deco(g(args): body)
          body
    

where (g := a) means a is assigned to the name g. As it turns out, functions
form a type which is a functor over the result type. The fmap (arrow map) is
just function composition. In Haskell you would write this as

    
    
        instance Functor ((->) r) where
          fmap g f = g . f
    

where the (.) syntax is also function composition, very similar to the @deco
syntax in Python. In this sense, I stated that @deco is a Functor.

Now, the function data type also admits a Monad instance (which some people
abuse terminology to say "functions are monads" but I highly dislike that
terminology when speaking carefully).

    
    
        instance Monad ((->) r) where
          return a = \_ -> a
          (f >>= g) x = g (f x) x
    

So in this way, the _function_ type instantiates both Functor and Monad, but
composition (which is (.) in Haskell and @deco is Python) is not directly
related to the Monad.

Instead, a function's Monad instance allows us to "defer application" and
translate something like

    
    
        \x -> (1 + x, 2 + x)
    

into

    
    
        do a <- (1+)
           b <- (2+)
           return (a, b)
    

In this format it's pretty stupid looking, but we also tend to call this monad
instance the "Reader Monad" which indicates computations which occur under a
fixed set of configuration information—some static global variables.

For instance, if I had a Key type which represented some encryption key I
could change my encrypt and decrypt functions from

    
    
        encrypt :: Key -> String -> String
        decrypt :: Key -> String -> String
    

to

    
    
        encrypt :: String -> Reader Key String
        decrypt :: String -> Reader Key String
    

which, allows us to defer that extra `Key` argument until later.

So, that's what I meant by saying that @deco isn't the Monad that its Functor
represents—it _only_ has the composition aspect, not the deferred application
aspect.

------
agscala
It seems like a good intro, but one of these days I would really like to see a
monad explanation that _doesn 't_ use Maybe.

~~~
FreezerburnV
What kind of example would you like to see other than Maybe?

~~~
jerf
List is probably the minimal intro you can do without trapping yourself. It's
too easy to implement something that can do the 1-or-0 elements in Maybe, but
still isn't a Monad. You should also do a conditional, which I believe this
code fails; that is, a monadic computation can examine the intermediate
results and make flow-control decisions.

The minimal example is probably something like:

    
    
        minimal :: Int -> [(Int, Int)]
        minimal i = do
            x <- [i, i + 1]
            y <- [i, 10 * i]
            if i `mod` 2 == 0
                then return (x, y)
                else return (y, x)
    

Running this in GHCi, I get:

    
    
        > minimal 2
        [(2,2),(2,20),(3,2),(3,20)]
        > minimal 3
        [(3,3),(30,3),(3,4),(30,4)]
    

The evenness or oddness of the parameter controls which side of the tuple gets
which element.

It may still be possible to implement this without implementing a full monadic
computation, but if you can pass this test using something like bind or join,
you're probably at least on the right track.

~~~
jerf
This conversation is dead, but I've expanded on this at
[http://www.jerf.org/iri/post/2928](http://www.jerf.org/iri/post/2928) .

------
vezzy-fnord
Is it bad if I find the null checks to be simpler in this particular scenario?

~~~
NDizzle
I hope not, for my own sake!

------
cliveowen
Sean Testes » A Gentle Intro to Gonads … Maybe?

Sorry, I had to.

