[racket] How to tell if identifier is bound in racket/load?

From: Ryan Culpepper (ryan at cs.utah.edu)
Date: Tue Jul 17 15:11:35 EDT 2012

On 07/16/2012 08:23 PM, Nick Sivo wrote:
>> I can't tell how the behavior you described differs from just providing the
>> variable from ark.rkt and requiring ark.rkt normally. Can you elaborate?
>
> Wow. I'm not sure what misconceptions I was working under, but that
> works completely fine.  And it looks like I can use something like
> defm from http://permalink.gmane.org/gmane.comp.lang.racket.user/13119
> to hide the getters and setters.
>
> Thanks!
>
> That said, I'd still like to be able to enable the equivalent of the
> following in arc:
>
> #lang racket/load
>
> (define (test1)
>    (displayln "a"))
>
> (define (test2)
>    (test1))
>
> (test2)
>
> (define (test1)
>    (displayln "b"))
>
> (test2)
>
> Welcome to DrRacket, version 5.2.1 [3m].
> Language: racket/load [custom]; memory limit: 128 MB.
> a
> b
>
> My current macro to handle top level assignment doesn't work in racket/load:
>
> #lang racket/load
>
> (require (for-syntax syntax/parse))
>
> ; From Danny Yoo's arctangent
> ; https://github.com/dyoo/arctangent/blob/master/language.rkt
> ; Returns true if stx is an identifier that is lexically bound.
> (define-for-syntax (lexically-bound? stx)
>    (let ([expanded (local-expand stx (syntax-local-context) #f)])
>      (cond
>        [(and (identifier? expanded)
>              (eq? #f (identifier-binding expanded)))
>         #f]
>        [else #t])))
>
> (define-syntax (assign1 stx)
>    (define-splicing-syntax-class binding-pair
>      #:description "binding pair"
>      (pattern (~seq var:id rhs:expr)))
>    (syntax-parse
>     stx
>     [(_ p:binding-pair)
>      (if (lexically-bound? #'p.var)
>          #'(begin (set! p.var p.rhs)
>                   p.var)
>          #'(begin (define p.var #f)
>                   (assign1 p.var p.rhs)))]))
>
> (assign1 a 5)
>
> When run, it never completes because lexically-bound? always returns
> false and recursion never terminates.
>
> If instead the assignment is in the body of a function, or in a
> module, it all works fine:
>
> (define (test)
>    (assign a 5)
>    a)
>
> Do these examples make my intent more clear?  I'm not sure how to
> describe what I want correctly.

I'm not sure how robust this solution is, but you could change the 
evaluation namespace to an empty module namespace. (Instead of an empty 
ordinary namespace, which is what #lang racket/load creates.)

In your example above, insert the following three lines right after the 
#lang line:

   (require racket/enter)
   (module scratch racket)
   (enter! 'scratch)

Then you could create your own language (arc/load?) that adds those 
lines (or something similar) automatically.

Ryan

Posted on the users mailing list.