[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [plt-scheme] assertions and the learning of macro-fu



At Sun, 12 May 2002 22:37:50 -0400, Don Blaheta wrote:
> (define-syntax (assert stx)
>     [...]
>     (syntax-case stx (assert not)
>       [(assert not x) (handle-assert stx #f (syntax (assert x)))]
>       [(assert x)     (handle-assert stx #t (syntax (assert x)))])))
>
> [...]
>
> Ok, now here's the weird thing that's got me completely stumped.  If you
> paste this into a mzscheme session directly, it works fine.  If you load
> it into mzscheme, it works fine.  If you put this into a module, and you
> require it from the interpreter prompt, then positive assertions (e.g.
> (assert 3)) work fine, but negative assertions give a syntax error:
> 
> Welcome to MzScheme version 200alpha12, Copyright (c) 1995-2002 PLT
> > (require "util.sch")
> > (assert #f)
> Assertion failed at STDIN: #f
> Value of #f is #f
> Aborting execution
> > (assert not 3)
> STDIN::53: assert: bad syntax in: (assert not 3)
> 
> 
> *However*, if you require it in another module, it works fine again:
> 
> (module temp
>         mzscheme
>         (provide (all-defined))
> (require "util.sch") ; includes assert
> 
>   (define (meef x)
>     (assert x)
>     (assert not x))
> 
> ) ; end module

Thie difference is the binding of `not':

 * Within a module that imports `mzscheme', the binding is to the `not'
   exported by `mzscheme'.

   Assuming that `assert' itself is defined within a module, then the
   literal part of the pattern match indicates the `not' exported by
   MzScheme.

 * Outside of a module, `not' refers to a top-level definition of
   `not'. The top-level defintion of `not' is the procedure exported by
   `mzscheme'. Even though it's the same value, they're different
   variables.

   In other words, the top-level environment is not initialized with
   `(require mzscheme)', but with `(namespace-require/copy 'mzscheme)'.

    A top-level `(require mzscheme)' would make the top-level use of
   `(assert not ...)' work.

I don't like this difference in bindings, of course. It's one place
where the R5RS-mandated semantics for top-level bindings is a poor fit
for the module system.


To fix the problem, change your pattern-matching rule to use
`module-or-top-identifier=?' (from the "stx.ss" library in the "syntax"
collection) for comparing literals:

 (require "stx.ss" "syntax")

 (define-syntax (assert stx)
     [...]
     (syntax-case* stx (not) module-or-top-identifier=?
       [(assert not x) (handle-assert stx #f (syntax (assert x)))]
       [(assert x)     (handle-assert stx #t (syntax (assert x)))])))

Another solution would be to compare `not's symbolically, ignoring
lexical bindings. That might be appropriate in this case, because `not'
isn't in an expression position (unlike `else' in `cond').

Matthew