[racket] redefining #%top (and #%app) with conditions

From: Matthew Flatt (mflatt at cs.utah.edu)
Date: Fri Feb 7 11:33:46 EST 2014

They're different `#%top`s.

In the the macro stepper, click on the first `#%top`, and the panel on
the right tells you that it comes from "bound.rkt". When you click on
the second `#%top`, though, the panel shows that it comes from
'#%kernel via `racket`.

At Fri, 7 Feb 2014 08:24:36 -0800, Matthew Butterick wrote:
> Last thing. This solution seems to work, but I can't figure out WHY it works.
> 
> If I look at these two lines in the macro expander, where bar is unbound:
> 
> (bar "hello")
> ((bound/c bar) "hello")))
> 
> First step makes sense: bar is replaced with (#%top . bar).
> 
> ((#%top . bar) "hello")
> ((bound/c bar) "hello")))
> 
> Second step makes sense: (#%top . bar) is replaced with my syntax-rule for 
> #%top to make an x-expression:
> 
> ((λ x `(bar , at x)) "hello")
> ((bound/c bar) "hello")))
> 
> Third step makes sense: (bound/c bar) is replaced with (#%top . bar).
> 
> ((λ x `(bar , at x)) "hello")
> ((#%top . bar) "hello")))
> 
> But in the fourth step, I get the "bar: unbound identifier in module" error. 
> This is what I want. But I don't understand is why this is so. Why wouldn't 
> the second (#%top . bar) get transformed by the syntax-rule attached to #%top?
> 
> 
> On Feb 6, 2014, at 9:37 PM, Matthew Butterick <mb at mbtype.com> wrote:
> 
> > Reflecting on it as an issue of detecting bound identifiers, I've come up 
> with a possible approach — could it be this simple, or am I overlooking some 
> complication?
> > 
> > bound.rkt:
> > 
> > #lang racket
> > 
> > (provide bound/c (rename-out (top~ #%top)))
> > 
> > (define-syntax-rule (top~ . id)
> >    (λ x `(id , at x)))
> > 
> > (define-syntax (bound/c stx)
> >    (syntax-case stx ()
> >      [(_ x)
> >       (if (identifier-binding #'x )
> >           #'x
> >           #'(#%top . x))]))
> > 
> > 
> > test.rkt:
> > 
> > #lang racket
> > (require "bound.rkt")
> > (define foo displayln) ; foo is now bound
> > (foo "hello")
> > ((bound/c foo) "hello")
> > (bar "hello") ; bar is unbound
> > ;((bound/c bar) "hello")
> > 
> > This does the right thing:
> > 
> > hello
> > hello
> > '(bar "hello")
> > 
> > And then when the last line is uncommented
> > 
> > ((bound/c bar) "hello")
> > 
> > It triggers the usual error on compile:
> > 
> > bar: unbound identifier in module in: bar
> > 
> > 
> > 
> > On Feb 6, 2014, at 8:38 PM, Matthew Butterick <mb at mbtype.com> wrote:
> > 
> >> I'm trying to figure out how to make #%top change behavior based on 
> different kinds of function names, though my experiments keep leading to 
> infinite loops that blow up DrRacket. Oops.
> >> 
> >> In my #lang project based on Scribble, I've been using this simple 
> redefinition of #%top for convenience:
> >> 
> >> (define-syntax-rule (#%top . id)
> >>   (λ x `(id , at x)))
> >> 
> >> IOW, if the thing in the function position is undefined, it's treated as 
> the opening tag of an x-expression. This makes it easy to mix undefined and 
> defined names.
> >> 
> >> But it can make debugging difficult. Because if you expect a name to be 
> defined as a function and it isn't, then you don't get the syntax error you 
> ordinarily would. The function call silently gets converted an x-expression. 
> Spooky side effects follow.
> >> 
> >> I'd like to improve this by making a syntactic prefix that suppresses this 
> behavior and that can be attached to any function name. For instance, def-*. 
> So if I write (def-foobar ..) in the code, this will mean:
> >> 1) try to invoke a function called (foobar ...); 
> >> 2) if the function (foobar ...) isn't defined, raise the usual exception + 
> syntax error.
> >> In other words, the standard #%top behavior.
> >> 
> >> Whereas if I just write (foobar ...) without the def-* prefix, this will 
> mean:
> >> 1) try to invoke the function (foobar ...); 
> >> 2) if the function (foobar ...) isn't defined, turn it into the 
> x-expression `(foobar ,@ ...). 
> >> In other words, my special #%top behavior shown above.
> >> 
> >> Having explained the logic, I think the flaw in my experiments so far is 
> that this actually requires manipulation of #%app too, because once you hit 
> #%top, you've missed your chance to apply functions. (Right?) But even 
> supposing one creates two evaluation paths under #%app, it's not clear to me 
> how to preserve those paths on the way up to #%top.
> >> 
> >> 
> > 
> 
> 
> ____________________
>   Racket Users list:
>   http://lists.racket-lang.org/users


Posted on the users mailing list.