You are on page 1of 12

Representing Monads*

Andrzej Filinski

School of Computer Science


Carnegie Mellon University
Pittsburgh, PA 15213-3891
andrzej +@cs. cmu. edu

Abstract [14, 16], they were quickly popularized by Wadler and


others aa a technique for structuring functional pro-
WJe show that any monad whose unit and extension grams [32, 18]. It is not hard to see the reason for this
operations are expressible as purely functional terms popularity: monads promise access to state, control op-
can be embedded in a call-by-value language with erators, 1/0, etc., while retaining the strong reasoning
“composable continuations”. As part of the develop- principles valid for pure functional languages. Briefly,
ment, we extend Meyer and Wand’s characterization of restricting programs to so-called “monadic style” (very
the relationship between continuation-passing and di- similar in spirit and appearance to continuation-passing
rect style to one for continuation-passing vs. general style) sets up a uniform infrastructure for represent-
“monadic” style. We further show that the composable- ing and manipulating computations with effects aa first-
continuations construct can itself be represented using class objects.
ordinary, non-composable first-class continuations and
It is somewhat remarkable that monads have had no
a single piece of state. Thus, in the presence of two
comparable impact on “impure” functional program-
specific computational effects – storage and escapes –
ming. Perhaps the main reason is that – as clearly ob-
any expressible monadic structure (e.g., nondet ermin-
served by Moggi, but perhaps not as widely appreciated
ism as represented by the list monad) can be added as a
in the “purely functional” community – the monadic
purely definitional extension, wit bout requiring a rein-
framework is already built into the semantic core of
terpretation of the whole language. The paper includes
eager functional languages with effects, and need not
an implementation of the construction (in Standard ML
be expressed explicitly. “Impure” constructs, both lin-
with some New Jersey extensions) and several examples.
guistic (e.g., updatable state, exceptions, or first-class
continuations) and external to the language (1/0, OS
1 Introduction interface, etc.), all obey a monadic discipline. The only
aspect that would seem missing is the ability for pro-
1.1 Background and overview grammers to use their own, application-specific monadic
abstractions – such as nondeterminism or parsers [31] –
Over the last few years, monads have gained consid-
with the same ease and naturality as built-in effects,
erable acceptance in the lazy functional programming
world. Originally proposed by Moggi as a convenient Actually, many of the useful monadic effects that are

framework for structuring the semantics of languages not already included can be defined in terms of existing
concepts in typical eager functional languages. For ex-
This
● research wss sponsored in part by the Defense Advanced
ample, backtracking can be expressed with call/cc and
Research Projects Agency, CSTO, under the title ‘(The Fox Project:
Advanced Development of S ystems Software”, ARPA Order No. 8313, an updatable st ack of backtracking points [5]. Still, such
issued by ESD/AVS under Contract No. F19628-91-C-0168. NSF also
implement ations appear ad-hoc, require a thorough un-
sponsored this research under grant no. CCR-8922109
The views and conclusions contained In this document are those of the derstanding of the imperative features used, and have
author and should not be interpreted as representing the official poli-
no clear connection to the “pure” monadic abstractions
cies, either expressed or implied, of the Defense Advanced Research
Projects Agency or the US. Government. they implement. And although all of the usual monads
seem to yield to this approach, it is far from obvious
Permission to copy without fee all or pert of this meterial is
that they must all do so.
granted provided that the copies we not mede or distributed for
direct commercial edventege, the ACM copyright notice end the In the following, we will show that in fact any
title of the publication and it? date appear, and notice i$ given monadic effect whose definition is itself expressible in
that copying is by permission of the Association for Computing
a functional language can be synthesized from just two
Machinery. TO copy otherwise, or to republish, raquires a fea
and/or specific permission, “impure’) constructs: first-class continuations and a

POPL 94- li94, Portland OrWort,USA


@ 1994 ACM tW39791-63WB4/Wl ..$3.~

446
storage cell. In other words, a language like Scheme In particular, our development is set in a simple call-
[2], or ML with first-class continuations [5], is already by-value (CBV) functional language based on “Moggi’s
“monadically complete” in the sense that any program principle”:
expressible in the somewhat contorted monadic style
can also can be written in direct style. Moreover, all Computations of type a correspond to values
of type TCY.
uses of computational effects in the definition can be en-
capsulated into an abstraction customarily called corn- Informally, ~a represents a “pure” (i.e., effect-free)
posable, functional, or partial continuations, and the re-
computation yielding a, while flt represents the com-
maining program contains no explicit references to ei-
putation consisting of t‘s effects followed by the result
ther escapes or state.
of applying f to the value computed by t.
The rest of this section contains a very brief intro-
As also noted by Moggi, the correspondence principle
duction to monads (a reader unfamiliar with the con-
can be embodied in an “introspective” language exten-
cept would be well advised to read one of the papers
sion which could be called monadic mjlect ion (by anal-
by Moggi or Wadler for a more complete presentation)
ogy to computational reflection [28, 34]), given by two
and Moggi’s convenient notation for monadic effects.
operators:
The following sections then derive the representation
result as a succession of three steps, each of which Ft-E:TcY I’1-E:a
and
is potentially useful in its own right and directly ex- rt-p(E):a r~[~l:zk
tends or supplements earlier work. First, we develop
For any E : T~, p(E) rejlects the value of E aa an
a formal correspondence between “monadic style” and
“effectful” computation of type a. Conversely, given a
continuation-passing style. Using this, we show that
general computation E : a, [El reifies it as the corre-
all non-standard manipulations of the continuation in
sponding “effect-free” value of type TCY.
“monadic CPS” can be expressed in terms of two opera-
For example, let T be the exception monad, defined
tors for composable continuations. Finally, we show how
as
to define these two operators using ordinary first-class
continuations and a piece of state. To supplement the
Ta = cr+exn
abstract development, section 5 presents the complete
q = k. inl a
embedding aa executable ML code and illustrates how
some common monadic effects can be uniformly repre- r = N.caset ofinla- fa[inre+inre
sented as instances of the construction. A comparison
(where exn is a type of exception names). Then P(E)
with related work and some conclusions complete the
expresses the value of E : CY+ exn aa a computation: we
paper.
get an exception-raising construct by

1.2 Monads and monadic reflection raise E ‘&f p(inr E)

For the purposes of “monadic functional programming”, (where E is an expression - typically just a value -of
a monad consists of a type constructor T and operations type exn). Conversely, [E] turns a possibly exception-
(polymorphic functions) raising a-expression E into a value of type a + exn, so
we can define an exception-handling construct like this:

El handle e a E2
called unit and extension, respect ivel y. ( Wadler uses a a~f case [.El] of inl a + a [ inre +E2
binary infix operator for the latter, writing m ‘bind’ f or
m A-f for our ~ m. His notation is probably superior for (i.e., if El raises an exception, the handler E2 is invoked
writing actual programs in monadic style, but the vari- with e bound to the exception name; a general pattern-
ant above seems preferable for the formal manipulations matching handle construct like SML’s can easily be
we will be performing.) The operations are required to expressed in terms of this one).
satisfy three monad laws: Justifying the designation as a “correspondence prin-
ciple”, monadic reification and reflection are inverses
m their respective domains. That is, for any expres-
sion E : @ (possibly With computational effects) and
any value V : Ta,

p([El) = E and [p(v)] = v


Monads can be used to give a semantics of various
“computational effects” (such as state, exceptions, or The more general not ation p(E) can be seen as sim-
1/0) in applicative programming languages [14, 16]. ply shorthand for let v = E in P(v), so in practice p(.)

447
would be provided as a function reflect : Ta + a. It is (where the last two, perhaps less familiar-looking, equa-
not necessary to have [.] as a special form either: we tions are taken from Moggi [14].) As an example of
can exploit the usual bijection between computations monadic reasoning, let us quickly check that the monad
of type a and values of type 1 --+ CYto get a function laws verify the correspondence principle for [.] and p(.):
reify : (1+ a) + TcY, extracting the monadic representa-
k([El)]T = id” [[E]]== id* (q [E]~)
tion from a suspended computation. For the theoretical
development in sections 2–4, however, we will keep the = (id” O q) [E]= = id [E’j~ = [I&
more compact p(0)/ [.]-notation.
Conversely, taking z as a representative value (the other
cases are analogous):
2 Monads and CPS

As the first step of our development, let us investigate


the formal connections between “monadic style” and
continuation-passing style (CPS). As noted by Wadler 2.2 The CPS translation
and others, the two appear closely related, but the ac-
tual correspondence is quite involved and benefits from Let us now consider the CBV CPS translation for the
a more detailed analysis. same pair of languages, and in particular still with re-
In this section, we consider two translations (monadic flection and reification operators for the monad T. The
and CPS) from a simply-typed CBV functional lan- translation on types looks similar:
guage with monadic reflection and reification operators
(our object language) into a “purely functional” meta-
/anguage: a typed Apv-calculus with monadic unit and
extension functions.
We then relate the two translations, generalizing the
results of Meyer and Wand [13] about the typed CPS where KY= (Y-+ To)-To for a type o of final answers.
(The key idea of making To the “new” answer type is
transform: their method can be seen as covering the par-
due to Wadler [32]), To get a simple relationship be-
ticular case where T is the identity monad (i.e., T~ = CX,
tween the two translations, we assume o to contain all
9 = ~d) and f*= f)
denotable values [22] (note that such an o does not have
to be a type expressible in the source language).1 Fur-
2.1 The monadic t ranslat ion
ther, to avoid clutter in the term equations, we omit
The monadic translation transforms an object-language inject ions into and project ions from o.
term E with free variables al,. ,., Xn, Now our source term E is translated into

Zl: al,..., xn:anl-E:~

into the meta-language term where the term translation is given by


Zl: [al]=, ..., z.: [an]. 1- [E]T : T~]~

The translation on types is given by:

[t]T = ,

[a -/& = [cY]~ + T[P]T


[T+ = T[a]~

Here t ranges over base types, and we use a - f? for The first three equations are the usual ones [19]. We
the CBV function space to distinguish it from the un- will verify that the last two really are the correct CPS
derlying “pure” function space a + P. The extension analogs of their T-translation counterparts next.
to structured types (products, sums, etc.) is straightfor.
ward but omitted here for brevity. The term translation 2.3 A relation between between monadic style
is given by and CPS
[z]T = qz Let us first note that we can define a type-indexed fam-
[k. E]~ = q(Jz. [J%) ily of functions mediating between monadic and CPS

[E, E,]T = (~f. f* [~2]~)* [~I]T 1Alternatively, with a little more care, we can t&e K-y =
Vo. (-y + To) + To; itis straightforward to check that both the
[P(~)]~ = ~~” [Ell~
term translation and the operations defined in the following can
[[El]T = q[E]T in fact be typed according to this schema.

448
translation), but since [.]K still specifies a CBV CPS
transformation, [~K (Az. Z) # U, and in fact there is
no functional way to “extract” U from [~ ~.
More abstractly, the problem is that we have actu-
ally introduced an effect (nontermination) in the source
language without a corresponding modification of the
monadic structure to encompass partiality. To rule out
such surprises, we need to make explicit use of the type
structure.
Specifically, for any source type a, we isolate a set of
“T-compatible” CPS values V. ~ [CY]K and computa-
(Meyer and Wand use the names i and j for functions tions C. G K[a]K, defined as follows:
analogous to $ and $, but the definition of $ given above
is slightly more convenient when T is not necessarily the
identity,)
It is straightforward to verify that (&, 07) form a
retraction pair, i.e., that for any source-t ype ~,

in the metalanguage. For ~ = t, the result is immediate;


for y =a -p: (Where qVa is the restriction of q to V*; the equation in
Ca means that the left-hand side is defined and equal to
the right-hand side). Part of the result we are aiming
for states that the K-meanings of all object-language
values and expressions are in fact T-compatible in this
sense.
The motivation for all the specific conditions is fairly
technical, but we can try to give some intuition. Most
importantly, if t c C@then

k* (tf) = k“ ([AC. c* (tq~e)]f) = k“ (f” (tqp)ti))


and for -y = Ta: = (k” o f)* (tq’pe)= t (k” o f)

and hence in particular

tk=k”(tqpa) = k“ (t(q O idva))


Thus the type translations faithfully embed the T- =t(k”oq oidva)= t(koidva)=tklva
Translation of a source-language type in the correspond-
ing K-translated type. But to properly relate the two (i.e., a Ca-term t only invokes its continuation with a
translations, we want the stronger property that the T- Ve-term, so that if k and k’ agree on V. then t k =
meaning of any source term can always be recovered t k’). The first condition for functions and the one for
from its K-meaning, i.e., that the CPS-translation re- TCY ensure that “latent” computations involving only
ally captures all the subtleties of the monadic one. V-terms (in particular, arguments of continuations) are
The proof of this property is more complicated than well-behaved when activated; note that the translation
might be expected: in particular, an attempt to prove it of M(E) can be written as
by induction on the term structure alone will not work.
To get a feeling for what goes wrong, consider the un- ~(E)]K = M. [E’JK (Am. [At. c* m]k)
typed variants of the translations with T as simply the
identity monad (so in particular, the p(.) and [.] oper- Finally, the second condition for functions expands to
ations have no effect). Now let U be any atomic value,
and consider the term

which states that a “well-behaved” function m can-


not itself depend on more information about its argu-
Then [~, = E = U (remember that we have full /3 in ment n than what is preserved by conversion back to
our met alanguage, even though [.]~ is nominally a CBV T-translated types.

449
It is easy to check by induction on types that 3 Monadic Reflection from Composable
Continuations

(so in particular if w = da (4O w) then w c V~). But The analysis in the previous section applies to an ar-
not every element of Va is of this form. For example, let bitrary monad T. But let us now make the natural
T again be the identity monad and consider the source assumption that the met a-language monad functions q
values and –* can actually be defined in the “pure” (i.e., effect-
free) functional sublanguage of our object language. In
other words, the definition of the monad must be suf-
Their T-meanings are equal, but their K-meanings are ficiently “algorithmic” that we can write a source pro-
not, so only one of the latter can be in the image of ~. gram in monadic style in the first place! If this is the
For a substitution u, let us write ill{a} (to avoid case, we say that the monad T is expressible in our lan-
yet another overloading of brackets) for the capture- guage.
avoiding application of u to a meta-language term M, As we have seen, we can express all monadic effects
and Ll{a o d} for (Af{cr}){d}. We can then state a key in CPS instead of in monadic style. A priori, this does
result relating CPS and monadic style. not leave us not much better off, however: to reach the
“non-standard” CPS terms used to interpret p(.) and
Theorem -Let zl:al, . . . . xn:cY~ k E : /3, and let u be
[.1 for any particular monad T, we still seem to need
a substitution assigning a V~t -term to each xi. Then
a T-specific translation phase (performed either manu-
ally, or by compilation, interpret atim, partial walua-
tion, or some other automated technique). But given
and
object-language terms for q and –*, it turns out that
[aT{JJ@ 0 ~} = [J%{m}(v 0%) we can represent all the required CPS terms in direct
(where +fi is the substitution mapping xi to tia,xi for
style extended with two fixed operators for manipulat-
l~i <n).
ing the continuation aa a “composable” function. Thus
The proof is by somewhat tedious structural induction every expressible monad can be simulated by a single,
on E (Meyer and Wand’s shortcut of only analyzing SK- “universal” effect which could be added to our object
combinators does not appear as useful in the general language once and for all.
case). As a direct consequence, we get: Specifically, we extend the source language of the CPS
translation with operators shift and reset, defined as fol-
lows:
In particular, if E is closed of base type (so @@is the
[SE]K = AK. [E]K (Af. f[Aw. AK’. K’(Rv)](Az.$))
identity), we have the simple equality [17JT = [E] ~ q.
More generally, using the above and the first half of the U+WL = ~~~([’5L (~~.~))
theorem, we get a monadic congruence result: shift captures (and erases) the evaluation context up to
k“ [E]. = [’qK{&} (~ “ d’fl) the nearest dynamically enclosing reset (every program
is run with an implicit all-enclosing reset), and passes
For example,in the case of the partiality monad [16],
this context to its argument as an ordinary function.
TCY = a u {1}, with k“ as the strict extension of k (i.e.,
For example:
k“ a = ka for a c a; k“ L = L), we recover the usual
restriction [25] that the continuation be strict to get 1 + #(2 X S(Ak. k(k 10)))
a congruence; the monadic characterization generalizes = l+letk= ~v.2xvink(k 10) = 41
this requirement to other computational effects.
(For our purposes, reset coincides wit h Felleisen’s
Finally, we can check explicitly that the reflection
prompt [6], whose #-notation we have adopted here; but
principle is satisfied when all free variables denote V-
shift differs from prom pt’s original companion cent rol (or
terms:
~) in that the continuation R is not given control over
[P(CEI)]K = Ak. [[El]~ k* = ~k. k“([-% v) = [EL # in the definition of S. ) For more details on shift/reset
and their relation to other notions of composable contin-
and
uations, see [3, 4, 17, 33]. As with the monadic [.], the
operation #. would typically be provided as a function
on thunks rather than aa a special form.
By our assumption that the meta-language q can be
Armed with a proof that the continuation-passing
included in the object language as a “pure” function of
characterization of monadic reflection and reification
type a - TCY, we have
faithfully represents the original definitions, we can now
return to the embedding result. [q]~ = ~k.k(h.~~.~(qa))

450
Similarly, extension is expressible aa a function of type 4 Composable Continuations from
(a - T@) - Ta - T~ that preserves “purity”: Storable Continuations

[f*lK = M. k(k. k. K($O*


a))
In the final step of our construction, we will see that
if [H ~ = Ak. k(Aa. AK. /c(pa))
shift and reset can themselves be defined in terms of non-
Now, in the CPS definition of [E] we want to evaluate composable continuations and a single storage cell. The
E with a continuation q, and only then propagate the trick is to view the CPS translation with continuation-
result to the surrounding evaluation context. This is in composing definitions of shift and reset as a direct-
fact almost what #, does – we only need to add the q: style specification of a language (with K as just another
higher-order function), and obtain from it a proper con-
lI#(~@L
tinuation semantics using a new “meta-continuation” -y,
= k. /c([qE]K (Xr. z)) as detailed in [3].
= k K ([q]K (~f. [E]K (~a. f a (~~. z)))) The result is displayed in Figure 1. (Here K is the

= AK. K([~K (Av. [~a. hc. %(qa)]v(h. z))) usual call/cc-operator which invokes its argument on the
current continuation represented as an escaping func-
= AK. /c([qK (h. (Az. z)(qv)))
tion, aa seen by the discarded K’.) Note in particular
= hc./C([lq Kq)
how the nested application K’ (K v) in the definition of
= [[El]K S is sequentialized into the usual J7”. K v (~w. IC’ wy”);
likewise, the outer K in [#E]K is put onto the meta-
Conversely, for p(E) we need to replace the current
continuation. On the other hand, all the underlined ~’s
continuation with its extended version, which again can
can actually be q-reduced away, so the metacontinua-
be directly expressed using S:
tion only really comes into play in shift and reset. The
[S(/M. k“ E)]K meaning of a complete program is now
= k. [~k. k“ E]K (~f. f (h. h’. /C’(K?J))(~Z. z))
$[qp,nit (Az. Ay. -y z) ‘y$n~~
= AK. [~k. [k” E] K](kJ. hC’./(KV))(~Z~Z. c)

= AK. [M. [k*]K (Ag. [E]x (h. ga (~c. z)))] where Yinit is the usual top-level continuation, typically
(~V.AK’. K’(KtJ)) simply the identity function.

= ht. [~K (h [h. AK’. K’(K* W)] U(~Z. Z)) First, let us note that given K, #, and the simpler
operator A (“abort”) with denotation
= k, [qK (Au. (Az. Z)(K* a))

= AK. [~K K“ 2[AE]P = k. ~~. c$[qp(h. kf’. +V)~

= [P(-E)L
[so AE is equivalent to S(M. E), where d @ IT’(E)],
(where k ~ FV(E)). This means that for any express-
we can express S as
ible q and —*, we can define [E] and p(E) in terms of
the composable-continuation primitives:
SE 2’ K(Ak. A(E(Az. #(kz))))

[El = #(qE)
(informally, the A erases the context once it is captured
P(E) ~’ S(M. k* E)
as k; and by wrapping a reset around k z, we ensure that
So if we only include shift and reset in our programming only the identity continuation gets discarded when k is
language, we can write all “monadic” programs in direct invoked). Thus, we only need to define A and #. (That
style. X, A, and # together suffice for defining all “pure” CPS

451
terms in a domain-theoretic setting was already noted 5 Implementation anti Examples
by Sitaram and Felleisen [2fl).
In this section we transcribe the abstract construction
‘The second, key observation is that – except for
presented so far into runnable code. To emphasize the
the definitions of A and # – the meta-continuation is
typing issues involved, we use the New Jersey dialect of
threaded through the meta-continuation semantics ex-
actly like the global store in a Scheme-like language! Standard ML [1] as our concrete language, but the oper-
ational content should translate straightforwardly into
This means that we we can simply designate a single,
Scheme as well (though instantiation to different mon-
updatable location to hold 7 (represented as a procedure
that ignores both the continuation and the metacontin- ads may be less convenient without a module facility).

uation passed to it), and only access it in A and #. We also give several examples; the reader may want to
compare these with Wadler’s presentation [32].
Specifically, in a language with continuations and
state, we have operations
5.1 Composable cent inuat ions

In SML/NJ, first-class continuations have a type dis-


tinct from the type of general procedures. Let us there-
fore first set up a representation of such continuations
as Scheme-style non-returning functions (this is not es-
(where u maps locations to values; &k is the location sential but makes for a more direct correspondence with
assigned to mk; mk := E evaluates E, stores the value, the semantics in section 4):
and returns (); and ! mk returns the current contents of
signature ESCAPE =
the cell without changing it). It is then easy to check sig
that the following definitions give terms with the right type void
val coerce : void -> >a
denotations: val escape : ((’la -> void) -> ‘la) -> ‘la
end;
AE %’ let v=E in !mkv [= (Av. !mk V)E]
structure Escape : ESCAPE =
#E %’ K(Jk.let m = !mk struct
datatype void = VOID of void
in (mk := (A~. (mk := rn; kT)); A.E))
fun coerce (VOID v) = coerce v
fun escape f $= callcc (fn k=>f (fn x=>throw k x))
(where let and ; are the usual abbreviations). Note end;

in particular that since k is an escaping function, the


For example, we can write
A-abstraction stored into mk in #E does denote a pro-
let open Escape
cedure that when invoked uses neither its continuation
in 3 + escape (fn k=>6 + coerce (k 1) ) end;
nor the current cent ents of m k. We also need to ini- (* val it = 4 : int *)
tialize m k to the initial continuation; the easiest way to
(The use of void and coerce instead of an unconstrained
do this is to simply wrap a reset around any top-level
type variable in escape permits storage of continuations
expression to be evaluated.
in ref-cells while staying within the ML type system [5].)
This completes our embedding of any expressible
Now we can define a composable-continuations facil-
monadic structure into a language with escapes and
ity, parametrized by the type of final answers:
state, a somewhat surprising result given the deceptively
general-appearing monad laws. It should be stressed signature COETROL =
again, though, that the construction only applies to sig
type ans
monads whose definitions can be captured as functional val reset : (unit -> ans) -> ans
programs in the first place: more esoteric effects like val shift : ((’la -> ans) -> ans) -> ‘la
end;
probabilistic computations defy such a simple decom-
position. functor Control (type ans) : COHTROL =
struct
Incidentally, the above definitions of shift and reset in
open Escape
terms of call/cc and and state could well have practical exception HissingReset
applications unrelated to monads. For example, Lawall val rek : (ans -> void) ref =
ref (fn -=>raise Hiss ingReset )
and Danvy are investigating applications of composable
fun abort x = coerce ( !mk x)
continuations for continuation-based partial evaluation
[12]; preliminary results indicate that using the embed- type ans . ens
fun reset t = escape (fn k=>let val m = !mk in
ded shift/reset instead of an explicit CPS transforma- mk := (fn r=>(mk := m; k r));
tion step can give significant improvements in time and abort (t () ) end)
fun shift h = escape (fn k=>abort (h (fn v=>
in space, when run under an efficient implementation of
reset (fn ()=>coerce (k v)))))
call/cc [9]. end;

452
For example, functor Represent (H : HOIAD) : RHOMAD =
struct
structure IntCtrl = Control (type ans = int) ; structure C = Control (type ans = Universal .u H .t )

let open IntCtrl structure 1! = H


fun reflect m = C. shift (f n k=>Pl. ext k m)
in i + reset (fn ()=>2 * shift (fn k=>k (k 10))) end;
(e val it = 41 : int*) fun reify t = H. ext (U unit o Universal from-u)
(C. reset (fn ()=>H unit
(Universal .to-u (t () ))))
end;
5.2 Monadic reflection

(Recall that operationally to_u and from-u are iden-


Building on the composable-continuations package, we
tities, and so is F!, ext H. unit. Also, it is worth stress-
implement the construction of Section 3. The signature
ing that only the implementation of Represent needs a
of a monad is simple:
typing loophole; its interface remains ML-typable and
signature HOIAD = safe.)
sig
type 9a t
val unit : ~a -> ~a t 5.3 Example: exceptions
val e~t : (Ja-> ~b t) -> ,at -> }b t
end; The example from the introduction becomes, in concrete
synt ax:
(the monad laws have to be verified manually, though).
structure Error? lonad =
Our goal is to define reflection and reification operations struct
for an arbitrary monad H to get datat ype ~a t = SUC of ~a I ERR of etring
val unit = SUC
fun ext f (SUC a) = f a
signature RHOHAD =
I ext f (ERR s) = (ERR s)
aig
end;
etructure H : HOIAD
val reflect : ‘la H.t -> ‘la
structure ErrorRep = Represent (ErrorHonad);
val reify : (unit -> ‘a) -> ‘a U.t
end;
local open ErrorMonad ErrorRep in
fun myraise e = reflect (ERR e)
Before we can proceed, however, there is one twist: our fun myhendle t h = case reify t of SUC a => a
lERRs=>hs
construction needs a universal type (the o of section 2.2): end;
(* val myraise = fn : string -> ‘la
eignature UIIIVERSAL = val myhandle = fn : (unit -> ‘a) -> (string -> ~a)
sig -> ~a *)
type u
val to-u : ~a -> u fun show t =
Val fr~~-u : u -> )~ myhandle (fn ( )=>”OK: “ - makestring (t () :int))
end; (fn s=> ’’Error: “ - s) ;
(e val show = fn : (unit -> int) -> etring *)

such that f rom_u o to_u is the identity for any Ba. shou (fn ()=>1 + 2);
(* val it = “OK: 3“ : string *)
(Note that ensuring that the instances of ‘ado in fact
match up dynamically now becomes our responsibility; show (fn ()=>1 + myraise “oops”) ;
the ML system is free to dump core on attempts to ex- (* val it = “Error: oops” : string *)

ecute code like 1 + f rem-u (to-u “f oo” ) ). This sig-


nature can be implemented in SML/NJ as 5.4 Example: state

The state monad with Wadler’s counting operations:


etructure Univereal : UIIVERSAL =
struct
functor StateHonad (type state) : HOEAD =
type u = System .Unsaf e object
struct
val to-u = System .Uneafe. cast
type ‘a t = state -> ‘a * state
val from.u = System .Unsaf e. cast
fun unit a = fn sO=>(a, sO)
end;
fun ext f m = fn sO=>let val (a, sl) = m sO
in f a 81 end
where cast behaves as an identity function, but has end;
the general type ‘a -> ‘ b.2 We can now complete the
structure Int St at eltep =
construct ion:
Represent (Stat eHonad (type state = int) ) ;
2 Even ~it,hout ~ fivem~ type, we still get a usable definition
fun tick () = IntStateRep. ref lect (f n s=> (() ,s+1) )
if we pick a suitable concrete type of answers. Then reification
fun fetch () = IntStateRep. ref lect (f n s=> (s ,s) )
becomes restricted to computations of that type, but reflection fun store n = IntStateRep .reflect (fn s=>(() ,n));
remains polymorphic; in many cases, e.g., in an interpreter where (* val tick = fn : unit -> unit
all evaluations happen at a single type of denotable values, this is val fetch = fn : unit -> ?. <Parameter> state (*= int*)
suilicient. val store = fn : int -> unit *)

453
functor ContFlonad (type answer) : HOEAD =
81 (IntStateRep. reif y (fn ()=> (store 5; tick () ; struct
2 * fetch ())) O); type ‘a t = ( ‘a -> answer) -> answer
(* val it = 12 : int *) fun unit x = fn k=>k x
fun ext f t = fn k=>t (fn v=>f v k)
end;

5.5 Example: nondeterminism


structure ContRep =
Represent (ContHonad (type answer = etring) ) ;
A nondeterministic computation can be represented as
a list of answers: local open ContRep in
fun myescape h =
reflect (fn c=>let fun k a = reflect (fn c ~=>c a)
structure ListHonad : HOEAD =
in reify (fn ()=>h k) c end)
st ruct
fun myshift h =
type ‘a t = ‘a list
reflect (fn c=>let fun k a = reflect (fn c>=>c~ (c a))
fun unit x = [x] in reify (f n ( )=>h k) (fn x=>x) end)
fun ext f [1 = [1
fun myreset t = reflect (fn c=>c (reify t (fn x=>x) ) )
lextf(h: :t)=fh Qextft
end;
end; (* val myescape = fn : ((~ia -> ~lb) -> ~la) -> JIa
val myshift = fn : (( ‘la -> string) -> string) -> ‘la
structure ListRep = Represent (ListHonad) ;
val myreset = fn : (unit -> string) -> string *)

local open ListRep in


ContRep. reif y (fn ( )=>3 + myeecape (f n k=>6 + k 1))
fun amb (x)y) = reflect (reify (fn ()=>x) @
makestring;
reify (fn ()=>y) )
(* val it = “4” : string *)
fun fail () = reflect []
end;
(* val ~b = fn : ~la * ~ia -> ~ia ContRep. reify (fn ()=>’’a” “ myreset (fn ()=>
“b” - myshift (fn k=>
val fail = fn : unit -> ~ia *)
k (k “C’’))))
(fn x=>x)
LietRep. reif y (fn ()=>let val x = amb (3,4) * amb (5 ,7)
(* val it = “abbe” : string *)
in if x >= 20 then x
else fail () end) ;
(* val it = [21 ,20,28] : int Listk!onad.t *)
6 Related Work
More generally, we get Haskell-style list comprehensions
“for free”, in that the schema The study of relationships between direct and contin-
uation semantics haa a long history. Early investigw

[Elz14-- El; . . ..zn+ En] tions [22, 25, 30] were set in a domain-theoretic frame-
work where the main difficulties concerned reflexive do-
(where each Z, maybe used in Ei+l, . . . . En and in E) mains; as a result, these methods and results seem
can be expressed directly as closely tied to specific semantic models. On the other
hand, Meyer and Wand’8 more abstract approach ap-
[let xl = p(E1) in . . . let z. = p(li?n) in E] plies to all models of (typed) A-calculi, but does not
encompass computational effect8 – not even nontermi-
For example, we can compute the “cartesian product” nation. The present extension of Meyer and Wand’s
of two lists aa retraction theorem to monadic effects should partially
bridge this gap, and add another facet to our under-
let open ListRep in
standing of CPS. It seems natural to expect other re-
reify (fn ()=>let val x = reflect [3, 4, 5] ;
val y = reflect [“’foo”, “bar”] sults about continuation-passing vs. direct-style to 8cale
in (x, y) end) up to monadic style as well; in particular, it should be
end;
(* val it = [(3,11 foot0) , (3,’’bar’$) , (4,’’foo”) , (4,’’bar”) , possible to extend the results presented here to lan-
(5,’’foo”) , (5 ,“bar”)] : (int ● string) list *) guages with reflexive types, perhaps by adapting one
of the semantics-based proofs mentioned above.
Of course, this is probably not the most efficient way of A possible equivalence between monads and CPS was
implementing list comprehensions in ML. As observed conjectured by Danvy and Filinski [3] and partially
by Wadler [31], however, list comprehensions can be fleshed out by Wadler [32], but even the latter was
generalized to arbitrary monads; similarly we get gen- quite informal – since the result generalizes Meyer and
eral monad comprehensions in ML simply by supplying Wand’s, one would expect the proof to be at least as
the appropriate [.] and p(,) operations. complicated. Another glimmer of the correspondence
can be seen in Sabry and Felleisen’s result [24] that

5.6 Example: continuations l%equivalence of CPS terms coincides with direct-style


equivalence in Moggi’s computational A-calculus [14],
Finally, let us consider the continuation monad (for an which captures exactly the equivalences that hold in the
arbitrary but fixed answer type): presence of arbitrary monadic effects. Peyton Jones and

[{54
Wadler [18] probe the relationship between monads and And perhaps even more importantly, it allows us to re-
CPS further, and Wadler [33] analyzes composable con- tain with no extra effort all the conveniences of the orig-
tinuations from a monadic perspective, but in both cases inal language, including pattern-matching, static type-
the restriction to Hindley-Milner typability obscures the checking, and module system. The efficiency of the
deeper connections. general embedding may not be quite as good as hand-
“Composable continuations” have also been studied coded monadic style specialized to a particular monad,
by a number of researchers [10, 8, 3]. Many of these especially since many compilers do not attempt to track
constructs depend on explicit support from the com- continuations across storage cells. On the other hand,
piler or runtime system, such as the ability to mark if effects are rare, programs run at full speed without
or splice together delimited stack segments. However, the overhead of explicitly performing the administrative
an encoding in standard Scheme of one variant was de- manipulations specified by q and –*, such aa tagging
vised by Sitaram and Felleisen [26]. The embedding is and checking return values in the exception monad.
fairly complex, relying on dynamically-allocated, muta- The embedding result is also a strong argument for
ble data structures, eq?-tests, and with no direct con- inclusion of first-class continuations in practical eager
nection to a formal semantics of the constructs. Yet an- languages, especially ones like ML that already have
other Scheme-implementable notion of partial continu- mutable cells: providing call/cc does not simply add “yet
ations was proposed by Queinnec and Serpette [20]; the another monadic effect” – it completes the language to
code required is perhaps even more intricate. (To be all such effects! Moreover, a sophisticated module sys-
fair, both of these constructs are apparently more gen- tem like SML’S lets us expose as little or as much of
eral than shift/reset, though the practical utility of this this underlying raw power as we need: by picking the
additional power remains to be seen.) The much simpler appropriate monadic structure, we can introduce effects
construction presented in this paper uses only a single ranging from simple exceptions to full composable con-
cell holding a continuation, and is directly derived from tinuations.
the denotational definition of shift and reset.
But surely there is more to “functional programming
Finally, recent work by Riecke [23] on effect delimiters
with escapes and state” than monadic effects. After
may be somehow related to the present paper, as they all, monads provide only the lowest-level framework for
share several concepts and techniques (specifically, mon- sequencing computations; in practical programs, we of-
ads, prompts, and retractions). On closer inspection, ten need tools for expressing higher-level, application-
though, the similarities become much less apparent (for oriented abstractions. A strict monad-based partition-
example, Riecke only considers a few specific monads
ing of effects may be adequate in many cases, but mon-
and attaches no special significance to CPS); cert airily
ads cannot and should not take place of a proper module
the specific goals of the two papers are quite different, facility. In fact, it might be that the syntactic “noise”
and the results obtained seem incomparable. Still, there
due to writing everything in monadic (or any other)
might be some deeper connections to uncover, and the
style makes it harder to recognize and exploit orga-
subject is probably worth exploring further.
nizational units that do not conveniently fit into the
monadic mold (for example, concurrency packages like
Reppy’s CML [21], or “imperative unification” using
7 Conclusions
mutable data structures).

By exploiting the correspondence between monadic and The present work also sheds some light on the prob-
continuation-passing styles, we can embed any definable lem of integrating individual monads to express com-
monad into a language with a ‘(composable continua- posite effects. Briefly, the complication is that a monad
tions” construct, Further, such a construct can itself be by itself is a closed package that contains too little infor-
decomposed into ordinary first-class continuations and mation: we need instead to express the monadic data

a storage cell. Thus, it is possible in principle to express as an increment to be layered on top of other possi-
any definable monadic effect as a combination of con- ble effects. How to do this uniformly is still not quite

trol and state. In practice, of course, many such effects clear; Moggi’s monad constructors [15] and Steele’s
– including, obviously, call/cc and ref-cells themselves – pseudomonades [29] are two possible techniques. In the
can be more naturally expressed directly, without the composable-continuations characterization of monads,
detour over composable continuations. monad combination seems to correspond to also letting

However, the construction presented here should still the target language of the defining translations con-

be of some practical use in experiments with, and rapid tain monadic effects, leading to the hierarchy of con-

prototyping of, more complicated monadic structures. trol operators and the associated metan-continuation-
The embedding approach does not incur the interpretive passing style introduced in [3] and further investigated

overhead of a “monadic interpreter” or the complexity of by Murthy [17].

an explicit source-to-source “monadic translation” step. However, such approaches all lead to an inherently

455
“vertical” or ‘{hierarchical” notion of monad composi- [5] Bruce F. Duba, Robert Harper, and David Mac-
tion, because in general we must answer such questions Queen. Typing first-class continuations in ML, In
aa “should backtracking undo 1/0?” or “should excep- Proceedings of the Eighteenth Annual ACM Sym-
tions undo state mutation?” (and perhaps also, “is this posium on Principles of Programming Languages,
really the right way to think about supposedly func- pages 163-173, Orlando, Florida, January 1991.
tional programs?” ) Yet many monadic effects can in
[6] Matthiaa Felleisen. The theory and practice of first-
fact be naturally combined in a “horizontal” or “inde-
class prompts. In Proceedings of the Fifteenth An-
pendent” way, such as different pieces of state, or stor-
nual ACM Symposium on Principles of Program-
age and 1/0; both the monadic and the (generalized)
ming Languages, pages 180–190, San Diego, Cali-
CPS formulation seem awkward in such cases, but indi-
fornia, January 1988.
vidually mutable cells capture this situation directly.
Much recent work on monads in “purely functional” [7] Matthiaa Felleisen and Robert Hieb. The revised
languages vs. control and state in an “imperative func- report on the synt attic theories of sequential con-
tional” setting seems largely disjoint. Perhaps the con- trol and state. Theoretical Computer Science,
nections outlined in this paper can lead to some cross- 103(2):235-271, September 1992.
fertilization and help avoid duplication of effort. For
example, “pure” functional programmers might benefit [8] Matthias Felleisen, Mitchell Wand, Daniel P. Fried-
from work on organizing and reasoning about first-class man, and Bruce F. Dubs. Abstract continuations:
continuations and storage cells in the “imperative” set- A mathematical semantics for handling full func-
ting (e.g., [7]); noting that these are monadic effects tional jumps. In Proceedings of the 1988 ACM
is clearly not sufficient to actually reason about them. Conference on Lisp and Functional Programmingj
Conversely, results about algebraic properties of partic- pages 52-62, Snowbird, Utah, July 1988.
ular monads (e.g., [11]) could be useful for recognizing
[9] Robert Hieb, R. Kent Dybvig, and Carl Brugge-
and exploiting patterns of continuation and state usage
man. Representing control in the presence of first-
in eager languages.
class continuations. In Proceedings of the ACM
SIGPLAN ’90 Conference on Programming Lan-
Acknowledgments guages Design and Implementation, pages 66–77,
White Plains, New York, June 1990.
I want to thank John Reynolds for support, and Olivier
[10] Gregory F. Johnson and Dominic Duggan. Stores
Danvy, Matthiaa Felleisen, Julia Lawall, Greg Morrisett,
and part ial cent inuat ions as first-class objects in
Amr Sabry, Phil Wadler, and the reviewers for their
a language and its environment. In Proceedings
helpful comments on various drafts of this paper.
of the Fifteenth Annual ACM Symposium on Prin-
ciples of Programming Languages, pages 158–168,
References San Diego, California, January 1988.

[11] David J. King and Philip Wadler. Combining


[1] Andrew W. Appel and David B. MacQueen. Stan-
monads. In J. Launchbury and P. M. Sansom,
dard ML of New Jersey. In Third International
editors, Functional Programming, Glasgow 1992’,
Symposium on Programming Language Implemen-
pages 134–143, Ayr, Scotland, 1993. Springer-
tation and Logic Programming, number 528 in Lec-
ture Notes in Computer Science, pages 1–13, Pas- Verlag.

sau, Germany, August 1991.


[12] Julia L. Lawall and Olivier Danvy. Continuation-
based partial evaluation. Indiana University and
[2] William Clinger and Jonathan Rees. Revised4 re-
Aarhus University. Personal communication, Octo-
port on the algorithmic language Scheme. Lisp
ber 1993.
Pointers, 4(3):1-55, July 1991.
[13] Albert R. Meyer and Mitchell Wand. Continua-
[3] Olivier Danvy and Andrzej Filinski. Abstracting tion semantics in typed lambda-calculi (summary).
control. In Proceedings of the 1990 ACM Confere- In Rohit Parikh, editor, Logics of Programs – Pro-
nce on Lisp and Functional Programming, pages ceedings, number 193 in Lecture Notes in Computer
151–160, Nice, France, June 1990.
Science, pages 219-224, Brooklyn, June 1985.

[4] Olivier Danvy and Andrzej Filinski. Representing [14] Eugenio Moggi. Computational lambda-calculus
control: A study of the CPS transformation. Math- and monads. In Proceedings of the Fourth Annual
ematical Structures in Computer Science, 2(4) :361– Symposium on Logic in Computer Science, pages
391, December 1992. 14-23, Pacific Grove, California, June 1989. IEEE.

456
[15] Eugenio Moggi. An abstract view of program- [25] Ravi Sethi and Adrian Tang. Constructing call-by-
ming languages. Technical Report ECS-LFCS-90- value continuation semantics. Journal of the ACM,
113, Laboratory for Foundations of Computer Sci- 27(3):580-597, July 1980.
ence, University of Edinburgh, Edinburgh, Scot-
[26] Dorai Sitaram and Matthias Felleisen. Control de-
land, April 1990.
limiters and their hierarchies. Lisp and Symbolic
[16] Eugenio Moggi. Notions of computation and mon- Computation, 3(1):67-99, January 1990.
ads. Information and Computation, 93(1):55–92,
[27] Dorai Sitaram and Matthias Felleisen. Reasoning
July 1991.
with continuations II: Full abstraction for models
[17] Chetan R. Murthy. Control operators, hierarchies, of control. In Proceedings of the 1990A CM Confer-
and pseud-classical type systems: A-translation at ence on Lisp and Functional Progmmming, pages
work. In Proceedings of the ACM SIGPLAN Work- 161-175, Nice, France, June 1990.
shop on Continuations, pages 49-71, San Fran-
[28] Brian C. Smith. Rejection and Semantics in a Pro-
cisco, California, June 1992. (Technical Report No.
cedural Language. PhD thesis, Massachusetts In-
STAN-CS-92-1426, Department of Computer Sci-
stitute of Technology, Cambridge, Massachusetts,
ence, Stanford University).
January 1982. MIT-LCS-TR-272.
[18] Simon L. Peyton Jones and Philip Wadler. Imper-
[29] Guy L. Steele, Jr. Building interpreters by compos-
ative functional programming. In Proceedings of
ing monads. In Proceedings of the Twenty-First An-
the Twentieth Annual ACM Symposium on Prin-
nual ACM Symposium on Pn”nciples of Pwgram-
ciples of Programming Languages, pages 71-84,
ming Languages, Portland, Oregon, January 1994.
Charleston, South Carolina, January 1993.
(To appear).
[19] Gordon D. Plotkin. Call-by-name, call-by-value
and the A-calculus. Theoretical Computer Science, [30] Joseph E. Stoy. The congruence of two program-

1(2):125-159, December 1975. ming language definitions. Theoretical Computer


Science, 13(2):151–174, February 1981.
[20] Christian Queinnec and Bernard Serpette. A dy-
namic extent control operator for partial contin- [31] Philip Wadler. Comprehending monads. Mathe-

uations. In Proceedings of the Eighteenth Annual matical Structures in Computer Science, 2(4):461-

ACM Symposium on Principles of Progmmming 493, December 1992. (An earlier version appeared

Languages, pages 174–184, Orlando, Florida, Jan- in Proceedings of the 1990 ACM Confewnce on

uary 1991. Lisp and Functional Programming).

[21] John H. Reppy. CML: A higher-order concurrent [32] Philip Wadler. The essence of functional pro-

language. In Proceedings of the ACM SIGPLAN gramming (invited talk). In Proceedings of the

’91 Conference on Programming Language De- Nineteenth Annual ACM Symposium on Princi-

sign and Implementation, pages 293–305, Toronto, ples of Programming Languages, pages 1–14, Al-

Canada, June 1991. buquerque, New Mexico, January 1992.

[22] John C. Reynolds, On the relation between direct [33] Philip Wadler. Monads and composable continua-

and continuation semantics. In Jacques Loeckx, ed- tions. Lisp and Symbolic Computation, 1994. (To
itor, 2nd Colloquium on Automata, Languages and appear).

Programming, number 14 in Lecture Notes in Com-


[34] Mitchell Wand and Daniel P. Friedman. The mys-
puter Science, pages 141-156, Saarbrucken, West
tery of the tower revealed: A non-reflective descrip-
Germany, July 1974.
tion of the reflective tower. Lisp and Symbolic Com-

[23] Jon G. Riecke. Delimiting the scope of effects. putation, l(l), May 1988.

In Functional Programming Languages and Com-


puter Architecture 1993, pages 146–155, Copen-
hagen, Denmark, June 1993. ACM Press.

[24] Amr Sabry and Matthias Felleisen. Reasoning


about programs in continuation-passing style. In
Proceedings of the 1992 ACM Conference on Lisp
and Functional Programming, pages 288–298, San
Francisco, California, June 1992. Revised version
to appear in Lisp and Symbolic Computation.

457

You might also like