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

From: Nick Sivo (nick at kogir.com)
Date: Mon Jul 16 20:23:07 EDT 2012

> 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.

-Nick

On Mon, Jul 16, 2012 at 10:43 AM, Ryan Culpepper <ryan at cs.utah.edu> wrote:
> On 07/16/2012 03:35 AM, Nick Sivo wrote:
>>
>> Hi,
>>
>> I've been using the following awesome snippet to detect when
>> identifiers are already bound:
>>
>> ; 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])))
>>
>> Then I created a helper so I could call it at runtime:
>>
>> (define-syntax (arc-bound stx)
>>    (syntax-parse
>>     stx
>>     [(_ var:id)
>>      (if (lexically-bound? #'var) #'#t #'#f)]))
>>
>> That still worked great.  Then I tried using racket/load:
>>
>> Welcome to DrRacket, version 5.2.1 [3m].
>> Language: racket/load; memory limit: 128 MB.
>>>
>>> (arc-bound a)
>>
>> #f
>>>
>>> (define a 5)
>>> (arc-bound a)
>>
>> #f
>>>
>>>
>>
>> :(  I've read through the docs on namespaces and the racket/load
>> language source in an attempt to fully understand why racket/load is
>> different, but I'm missing something.  I've noticed that I can see 'a
>> in (namespace-mapped-symbols), and have tried using that, but ran into
>> (I think) phase issues.  If there's a quick solution to this that I've
>> missed, that's brilliant.
>
>
> It works in DrRacket using #lang racket because the interactions occur in a
> module namespace, but with #lang racket/load all interactions happen in an
> ordinary namespace. That accounts for the differences in the results of
> identifier-binding.
>
>
>> Otherwise, my motivation to start making use of racket/load (really
>> arc/load in my case), is to get access to global variables.  If
>> ark.rkt declares something at the module level, I need to be able to
>> see it - the same copy of it - from other modules that require
>> ark.rkt.  What I'm trying now is to have ark.rkt be a real module
>> written in arc, and then require it and load the rest of the arc files
>> using the arc/load language so they all share the same module registry
>> and the same ark.rkt.  If there's some other, better way to do this,
>> pointers will be quite warmly received.
>
>
> 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?
>
> Ryan

Posted on the users mailing list.