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:
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 monadM
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 typeint
, and we produce a new typeM<int>
.A generic function
unit
which accepts a value of typeT
and produces a value of typeM<T>
.A generic function
bind
which accepts a value of typeM<T>
and a function fromT
toM<U>
, and produces anM<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.