Re: Metaprogramming using Scheme



Jonathan Bartlett wrote:

> Wrong as in "bad style" or "leads to undefined/unintended results"?

Wrong as in "leads to undefined/unintended results". The identifiers
are not introduced correctly. The example:

(define-syntax with-math-defines
(lambda (x)
(syntax-case x ()
((with-math-defines expression)
(with-syntax
((expr
(datum->syntax-object
(syntax k)
`(let ( (pi 3.14) (e 2.72))
,(syntax-object->datum (syntax expression))))))
(syntax expr))))))

has two things wrong with it. First, the k in (syntax k) should
refer to the context where the macro call occurred (otherwise the
macro will break when using modules, etc.). Fixing this, let's write:

(define-syntax with-math-defines
(lambda (x)
(syntax-case x ()
((k expression)
(with-syntax
((expr
(datum->syntax-object
(syntax k)
`(let ( (pi 3.14) (e 2.72))
,(syntax-object->datum (syntax expression))))))
(syntax expr))))))

But now we have lost referential transparency. For example,
the following give errors:

(let ((let 0))
(with-math-defines
(* pi e)))

==> procedure application: expected procedure,
given: 3.141592653589793

(let ((x 0))
(let-syntax ((bar (syntax-rules ()
((_ exp)
(with-math-defines exp)))))
(let ((x 1))
(let-syntax ((foo (syntax-rules ()
((_) (bar x)))))
(foo)))))

==> 0 instead of the correct answer 1

The correct way to introduce these variables, while preserving
hygiene and referential transparency, is

(define-syntax with-math-defines
(lambda (x)
(syntax-case x ()
((k expression)
(with-syntax
((pi (datum->syntax-object (syntax k) 'pi))
(e (datum->syntax-object (syntax k) 'e)))
(syntax
(let ((pi 3.14) (e 2.72))
expression)))))))

(let ((let 0))
(with-math-defines
(* pi e))) ==> 8.5408

(let ((x 0))
(let-syntax ((bar (syntax-rules ()
((_ exp)
(with-math-defines exp)))))
(let ((x 1))
(let-syntax ((foo (syntax-rules ()
((_) (bar x)))))
(foo))))) ==> 1


Similar considerations apply to the cgi-boilerplate macro.

Regards
Andre

.



Relevant Pages

  • Re: Scheme macros
    ... > selectively break hygiene. ... > defmacro can do, but from the opposite direction: ... the syntax-case approach ought to be ... LOOP macro which covers the presumably important cases. ...
    (comp.lang.lisp)
  • Re: scheme seems neater
    ... For a beginner, syntax-rules is at least as easy to understand as defmacro, ... Hygiene is not an issue, ... understand how systems like syntax-case work. ... Part of the point of these macro systems was also to constrain ...
    (comp.lang.lisp)
  • Re: Scheme macros
    ... > That's what all of these macro systems are. ... > The same is true of syntax-case. ... Here are the examples from that reference implemented with DEFMACRO: ... Lisp and Scheme bring you metacircularity. ...
    (comp.lang.lisp)
  • Re: How to think about Scheme macros, was Re: scheme seems neater
    ... Given syntax-case, syntax-rules is theoretically redundant, but when all you ... and makes the macro a ... To be more PC, lexically-aware macros could ... But as you've gathered, I would emphasize lexical scope over hygiene, ...
    (comp.lang.lisp)
  • Re: Scheme macros
    ... I don't know much about the Scheme macro system ... ... It's not only hygiene. ... Syntax-case is a rich system that's hard to summarize briefly, ...
    (comp.lang.lisp)