The Paradox of Partial Parametricity

Claus Reinke claus.reinke at
Thu May 30 06:15:19 PDT 2013

> The fact that we can make it monadic is just a bonus; any time you see
> "monad" just think "container++" - it's just a proven useful bit of
> structure on top which makes it easy to work with the values inside
> the container.  (It's a bit more abstract than that, of course, but
> thinking in terms of containers works for many monads, and helps 
> guide understanding toward the more abstract notion.)

You are aware of the over-simplification in that suggestion, but it
can still be harmful to readers here (who may dismiss the simple 
examples and never get to the abstract notion). So, please pardon
a little elaboration/clarification:

Monads are not about containers. Even functors (map-supporting 
things) are not about containers. That is confusing class-level 
constructs (Array<String>) with object-level constructs  (["hi"]) and 
misses out on some of the most interesting applications of monadic 
coding. The container analogy stops working when class-level 
constructs correspond to object-level control structures (eg, 
mapping over a promise means attaching a post-processor).

To give a use-case relevant to ES6 language design: generators were
carefully designed to capture the flattest continuation that allows to
stop and resume code in ES control structures without changing them. 
Monadic code captures even flatter continuations, and allows to define 
equivalent control structures in libraries, including generators and
exceptions. In other words, good support for monadic coding allows
to move language design decisions to libraries, and gives library
authors expressive powers formerly reserved to language designers.

Monads first use case in programming languages was modular
specification of language semantics for features like exceptions
and non-determinism. That was then translated into modular
program design for things like parsers, solution search, and
embedded language interpreters. Some of the coding patterns
go back to the 1980s, at least, but bringing them under the 
common head of monads and coding against a common monadic 
API started in the early 1990s. 

This latter development allowed to work out commonalities between 
these coding patterns as well as sharing of code between control
structure implementations: whether you need to implement a parser, 
embed a prolog interpreter, support exceptions, implement a type 
system, or a strategic rewrite library for code analysis and 
transformation passes - in the past, you started from scratch each
time, these days, a good monad library gets you most of the way, 
provides valuable design guidelines, and pushes towards modular 
specifications and implementations. 

In effect, monads and their cousins have started to give us similar 
structuring, sharing, and reuse tools for control structures as those
we take for granted for data structures. 

And because monads have helped us to see commonalities in 
different control-structure problems and their solutions, adding 
language support for monadic code supports all of these solutions 
at once. Instead of languages growing bigger with problem-specific
constructs (generators, exceptions, promises, ...), languages can grow 
simpler again, off-loading specific solutions to library code while 
adding generic expressiveness to the language.

A lot of the early practical adoption of monads happened in a 
non-strict language, where data structures can stand in for control 
structures (eg, lazy lists for infinite iterators or promises). Also,
monads where the class-level constructors corresponds to a simple 
object-level constructor are easier to present in monad tutorials. So 
it has become popular to present monads to containers with extras, 
but that is a very limited view. And it does not explain why monads
have become so important to language designers and library
authors alike.



More information about the es-discuss mailing list