Functional Programming – Minimal Programmer’s Definition of a Monad

functional programmingjavascriptmonad

I am trying to formulate a definition of a monad without needing mathematical terms or Haskell to understand.

Can a monad be thought of as a function that accepts a value and wraps it such that it meets specific interface and behavioral constraints that have been found to be useful when working in a functional style?

The interface constraints are:

i. It has a type constructor that defines its type (What is this?).

ii. It has a unit function that converts a value to its corresponding monadic type.

iii. It has a "bind" method that takes a monad, a function that takes a some type and returns a monad (is this another monad?), and returns a monad.

The behavioral constraints are:

i. Left identity

Monad(x).bind(fn) == Monad(fn(x)); // for all x, fn

ii. Right identity

Monad(x).bind(function(x){return x;}) == Monad(x); // for all x

iii. Associativity

Monad(x).bind(fn1).bind(fn2) == Monad(x).bind(function(x) {
  return fn2(fn1(x));
});

Is this a minimal definition of a monad?

Best Answer

Mason's answer is correct, and yes you should read my series. To emphasize his point more thoroughly:

Can a monad be thought of as a function that accepts a value and wraps it such that it meets specific interface and behavioral constraints

Yes, but that is not the best way to characterize a monad. You are very close though; we can make small changes to your formulation and arrive at a better characterization.

You say a monad, call it M, is a function that accepts a value and produces a wrapped value. It is the is that is problematic. Rather, a monad has such a function. A monad M is a collection of three things:

  • A transformation that takes a type and produces a new type. In C# we call such a transformation a "generic type". We have a generic type M<T>, we have a type int, and we produce a new type M<int>.

  • A generic function unit which accepts a value of type T and produces a value of type M<T>.

  • A generic function bind which accepts a value of type M<T> and a function from T to M<U>, and produces an M<U>.

That second thing is your "function which accepts a value and wraps it". It's not that a monad is that function; a monad is the combination of the monadic type constructor itself, the wrapper, and the function which binds a new function onto the end of a monadic workflow.

This is why in category theory, monads are sometimes called "triples"; because you need three things to characterize a monad.

Now, you'll note that I do the same thing as you; in my series of articles I characterize a monad as a generic type that obeys certain rules; that is, I say that the monad is the first thing, and that first thing must itself have the second and third things.

How exactly we characterize the relationships between the parts doesn't really matter; what matters is that there must be these three things: a way to "amplify" types, a way to "wrap" values, and a way to transform an instance of a monad into to another by "binding" a function onto it. If you have those three things, and they obey the obvious rules for identity, transitivity, and so on, then you have a monad.