Monads (Re: [challenge] Limitation in D's metaprogramming)

Jonathan M Davis jmdavisProg at gmx.com
Tue Oct 19 12:58:03 PDT 2010


On Tuesday 19 October 2010 12:13:19 Graham Fawcett wrote:
> Hi Jonathan,
> 
> On Mon, 18 Oct 2010 18:02:58 -0700, Jonathan M Davis wrote:
> > On Monday, October 18, 2010 17:54:50 Nick Sabalausky wrote:
> >> "Jonathan M Davis" <jmdavisProg at gmx.com> wrote in message
> >> news:mailman.715.1287449256.858.digitalmars-d at puremagic.com...
> >> 
> >> > One word: monads.
> >> > 
> >> > Now, to get monads to work, you're going to have to be fairly
> >> > organized about it, but that would be the classic solution to not
> >> > being able to have or alter global state and yet still be able to
> >> > effectively have global state.
> >> 
> >> Oh yea, I've heard about them but don't have any real experience with
> >> them. Any FP experts know whether or not monads are known to be
> >> constructible from purely-FP building blocks? I always assumed "no",
> >> and that monads really just came from a deliberate compiler-provided
> >> hole in the whole purity thing, but maybe I'm wrong? (That would be
> >> quite interesting: constructing impurity from purity.)
> > 
> > You can think of a monad as an extra parameter which is passed to each
> > function and holds the global state. It isn't a hole in purity at all.
> > For instance, it's how Haskell manages to have I/O and yet be
> > functionally pure. You don't need the compiler's help to do monads -
> > it's just easier if you have it.
> 
> I don't see how monads will help here. Monads are useful for threading
> state through pure computations, and are an enabler for I/O in Haskell
> by threading the "real world" through a computation as a series of
> computational states. Something has to initiate the thread, and tie it
> up at the end: there's an implicit scope here, and I think here's
> where the hard questions start to crop up in the context of CTFE.
> 
> Without permitting I/O, you could use a state-carrying monad to
> implement a kind of dynamically-scoped namespace during CTFE; the
> dynamically-scoped, mutable values would be global from the internal
> perspective of the CTFE computations, but they would not leak out of
> the monad into "truly global" state; and the overall effect would be
> pure.
> 
> So, you can achieve an implicit, dynamic scope using monads. But if
> all CTFE expansions are done within a single such scope, it would be
> indistinguishable from running all CTFE expansions with access to
> globally shared state (though not I/O). So then, why not just use
> global state? Therefore, the monads could only practically be used as
> an isolation technique, to isolate dynamically scoped values during
> different CTFE expansions -- for example, at a compilation-unit level
> -- without sacrificing purity. But then, it seems you would lose the
> very thing you need to implement the challenge on the table: two
> modules would want access to the same counter during expansion, not
> two isolated copies of the counter. So again, you're back at global
> state, or mimicking it using a state-carrying monad, with no
> significant benefits accomplished by using a monad.
> 
> Just my two cents,
> Graham

I haven't really looked in detail at how you'd solve the problem in question, 
but I believe that you'd pretty much have to chain all of the initializations so 
that there is a clear one which is initialized first and that each successive 
initialization relies on the previous one, with the monad being passed along 
through each. I believe that that would work between modules as well, though I'm 
not 100% certain. Regardless, the solution is rather messy because you have to 
have the monad specifically passed along everywhere and have a fairly explicit 
ordering to the instantiation (though you might be able to decouple it a bit if 
all you care about was the final count and some of the initializations depended 
on multiple other instantations and combined their monads), so it's not a 
particularly pretty solution even if it works. However, if you're trying to have 
state in an effectively stateless environment, that's pretty much the only way 
that I know to go about doing it. What you really need is some sort of global 
state for CTFE, but static initialization is specifically designed so that it 
doesn't have global state (if nothing else to avoid order issues screwing with 
initializations), so I don't really see that happening any time soon, if ever.

- Jonathan M Davis


More information about the Digitalmars-d mailing list