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 ,@x)) "hello")
((bound/c bar) "hello")))

Third step makes sense: (bound/c bar) is replaced with (#%top . bar).

((λ x `(bar ,@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 <m...@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 ,@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 <m...@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 ,@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

Reply via email to