From posting-system@google.com Tue Aug 26 19:01:47 2003
Date: Tue, 26 Aug 2003 12:00:45 -0700
From: oleg-at-pobox.com
Newsgroups: comp.lang.scheme
Subject: Re: monads and reflection [was: overloading]
References:
<7eb8ac3e.0308251027.4773d026@posting.google.com>
Message-ID: <7eb8ac3e.0308261100.493e0906@posting.google.com>
X-Comment: slight editing.
Status: OR
"David A. Herman" wrote in message
news:...
> I've heard some warnings about the constructions this paper uses,
> namely monadic reflection.
Monadic reflection is the "running" of a monad. When you see "runST",
for example, in Haskell code, you see the monadic reflection. The
function getChar, for example, is the result of a reification of an
I/O action. The function represents an effect as a pure value (IO
Char). The function unsafePerformIO turns (i.e., reflects) that value
into an effect.
Filinski uses a slightly different notation for bind: he writes
"m >>= f" as "f* m" (that is, he flips the operands). That notation
might be less convenient for practical applications, but far more
insightful. Indeed, we can read '*' as a binary operator:
(*):: (a->M b) -> M a -> M b
OTH, we may consider (*) as an unary postfix operator. Then "(f*) m" is
a regular application. That postfix (*) has the type
(*):: (a->b) -> (M a -> M b)
which is just fmap. If we have a function f::a->b that takes a to b
and has an effect, we get the monadic (lifted) function
f*:: M a -> M b
as f* = \m -> reify(f (reflect m))
The function f* no longer _does_ any effects: it merely _denotes_ them.
In Scheme, one may think of 'delay' as reify and 'force' as reflect.
> But I'm not sure if Scheme and monadic style are a good fit for each
> other. Using Haskell's type inference in conjunction with overloaded
> monad operations and do-notation strikes me as an elegant approach.
Yes, but so is Scheme. Let us consider running the following chain of
MonadPlus:
m1 >>= f1 >>= f2 >>= f3 >>= f4
Suppose, f1 did "fail". Haskell still has to execute the rest of >>=
statements to propagate that exception till the end. In contrast, in
Scheme, when we do shift, we literally skip over all remaining
applications, till the closest (in the dynamic scope) reset.
Monads in Haskell induce a separate, CPS-like, sublanguage. Bind,
(>>=) denotes an application in that language. Because all terms in
that language are CPSed, we get the sequential execution even if the
host language is non-strict (Plotkin's indifference theorem). As
Filinksi, and Moggi before him, observed, in a strict language with
effects the language itself enforces the sequential discipline, so we
do not need any extra contortions in the forms of explicit Monads.