The main advantage of this style is that it hides the
explicit continuations that would normally be required for
composable macros. Also, some people may find the do#-syntax
easier.
Just as in lazy languages, the monadic style is used here to
control evaluation order. This is done with the do#-notation,
which can be thought of as a sequential let* at the macro level.
Examples:
(define-monadic-syntax cons# ()
[(cons# h t) (return# (h . t))])
(define-monadic-syntax append# ()
[(append# () y) (return# y)]
[(append# (h . t) y) (do# ((z (append# t y)))
(cons# h (??! z)))])
(define-monadic-syntax reverse# ()
[(reverse# ()) (return# ())]
[(reverse# (h . t)) (do# ((x (reverse# t)))
(append# (??! x) (h)))])
(run# (reverse# (1 2 3 5 list)))
;==> (5 3 2 1)
(define-monadic-syntax compose-rev# ()
[(compost# m1 m2) (do# ((x (reverse# m1))
(y (reverse# m2)))
(append# (??! x) (??! y)))])
(run# (compose-rev# (1 2 list) (3 7 9)))
;==> (2 1 9 7 3)
Andre van Tonder
Code below:
;=============================================================
; Definitions for monadic-style R5RS macros:
; By Andre van Tonder
; Relies on Oleg Kiselyov's macro-level ??!lambda and ??!apply
; at http://okmij.org/ftp/
(define-syntax define-monadic-syntax
(syntax-rules ()
((define-monadic-syntax name lits
[(_ arg ...) (form . args)] ...)
(define-syntax name
(syntax-rules lits
[(_ k arg ...) (form k . args)] ...)))))
(define-syntax return#
(syntax-rules ()
[(return# k exp) (??!apply k exp)]))
(define-syntax do#
(syntax-rules ()
[(do# k ((x (form1 . args1))) (form2 . args2))
(form1 (??!lambda (x) (form2 k . args2)) . args1)]
[(do# k (bind1 bind2 ...) body)
(do# k (bind1) (do# (bind2 ...) body))]))
(define-syntax run#
(syntax-rules ()
[(run# (f . args))
(f (??!lambda (x) (??! x)) . args)]))
;==============================================================
; Some tests:
(define-monadic-syntax cons# ()
[(cons# h t) (return# (h . t))])
(define-monadic-syntax append# ()
[(append# () y) (return# y)]
[(append# (h . t) y) (do# ((z (append# t y)))
(cons# h (??! z)))])
(run# (append# (list 1 2) (4 5 7)))
;==> (1 2 4 5 7)
(define-monadic-syntax reverse# ()
[(reverse# ()) (return# ())]
[(reverse# (h . t)) (do# ((x (reverse# t)))
(append# (??! x) (h)))])
(run# (reverse# (1 2 3 5 list)))
;==> (5 3 2 1)
(define-monadic-syntax compose-rev# ()
[(compose-rev# m1 m2) (do# ((x (reverse# m1))
(y (reverse# m2)))
(append# (??! x) (??! y)))])
(run# (compose-rev# (1 2 list) (3 7 9)))
;==> (2 1 9 7 3)
That is very neat!
> Just as in lazy languages, the monadic style is used here to
> control evaluation order. This is done with the do#-notation,
> which can be thought of as a sequential let* at the macro level.
Indeed, both monads and CPS provide a sublanguage that is indifferent to
the evaluation order (call-by-name or call-by-value). That's why
monads are so useful in a lazy language, and considerably less useful
in an eager language (as noted by Moggi and Filinski).
It seems there is another interpretation of your construction:
A-normal form. Your macros follow the grammar of the A-normal
form. The do# notation is a (particular) translation from an A-normal
form to CPS.