Monads in dynamic languages
Published on
Are monads possible outside of Haskell?
Of course, it depends on what you call a monad.
The definition that is usually accepted in the Haskell context — that
a monad is an instance of the particular type constructor class,
Monad
, with two methods satisfying three laws — is very
much tied to Haskell’s language features — most importantly, types, type
constructors and type constructor classes. Hence, this or similar notion
of monad can only exist in a language rather close to Haskell.
If we drop the type constructor class requirement, then a monad is a
triple consisting of a type constructor M
and two
polymorphic functions
return :: forall a . a -> M a
(>>=) :: forall a b . M a -> (a -> M b) -> M b
This is the definition originally used by Wadler in The essence of functional programming. By this definition, Monads can be implemented in other Hindley-Milner based languages, like Miranda and ML.
But what if we take this to extreme? What if we consider a dynamically typed functional language?
A dynamically typed language is nothing
else than a static language with a single type, which we shall call
here U
. Thus, the signatures of >>=
and
return
become
return :: U -> U
(>>=) :: U -> (U -> U) -> U
(We could as well say that >>=
and
return
both have type U
— remember, there’s
only one type!) The functions themselves are still presumed to satisfy
the usual laws.
This has been done many times before, most recent example being Douglas Crockford’s keynote at YUIConf. Douglas’s presentation has received a lot of criticism (and I’m not going to defend him), but some critics even have expressed the doubt that these are not «genuine» monads.
To settle this, let’s turn to the category theory — after all, that’s where monads come from. Haskell’s monads are category theory monads, where the type constructor is considered as an endofunctor on Hask, the category of Haskell types and functions.
What changes when we go from Haskell to a unityped language is that
all the diversity of Haskell types collapses into the single type,
U
. That doesn’t stop it from forming a category, though.
Because it has a single object, we don’t need a type constructor to
represent the functorial action on objects — it’s always identity. We
only need to know the functorial action on arrows (called
fmap
in Haskell) — but it is already determined by
return
and >>=
.
To summarize, there doesn’t seem to be any reason to think that monads are somehow impossible in dynamic functional languages. And, although Haskellers usually consider monads as something closely tied to types, in a dynamic language all you need to define a monad is to define a pair of functions satisfying the monad laws.