2008-12-11 12:15:18 UTC
group's file section. I have now replaced it by a more or less complete
rewrite. This rewrite was motivated by one serious problem with the
original implementation, plus a number of minor points that I was not
happy with. I have also integrated some ideas from Jim's alternative monad
implementation. The new implementation has replaced the original one at
In my original implementation, I had used keywords for the monad
operations. These keywords were replaced by their definitions inside a
given monad using a recursive symbol replacement in the form to be
evaluated. This approach has a major problem: it doesn't combine correctly
with macros. If a macro expands into a form containing monad operation
keywords, they are not replaced at all, because my symbol replacement code
sees only the original form.
The new implementation uses plain functions for the monad operations. The
expands into a straightforward let form that binds the operations to their
names. Generic monad operations such as lift are implemented as functions
that take the four basic monad definitions as additional parameters. These
functions are wrapped by macros that add these parameters to the argument
list. In the new implementation, all form manipulation is done by macros,
and there is much less of it: it no longer has a fundamental role, but
just provides nicer syntax.
To pursue my original idea of a replacement-based implementation, one
would need something like Common Lisp's symbol-macrolet, which is however
not trivial to implement. It requires either an integration with the
compiler's macro expansion mechanism, or a separate implementation of full
macro expansion, including subforms, of an arbitrary form.
With the new monad implementation, client modules can:
- define new monads (monad and defmonad)
- define new generic monad operations (defmonadfn)
- execute code using a monad (with-monad)
- define functions that internally use a specific monad (define the
function inside a with-monad block)
- use monad comprehension syntax (domonad)
Some minor changes:
- All monad operations have names starting with m-.
- There is a single m-lift that takes its arity as an argument.
- m-plus takes an arbitrary number of arguments and respects lazy evaluation.