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