[racket] obtaining the location of an identifier
If you get a good solution, please let the rest of us know. For the new
simulation collection, I need to be able to maintain statistics and history
for selected 'variables'. I currently do this with a struct and a
prop:procedure to implement a getter and setter. This requires using the
struct instance as a procedure - i.e., it is parenthesized like a
parameter. This works and I can use it in any context. But, it would be
nice to have a mechanism that provided the same capability without the
procedure syntax that worked in all contexts.
Doug
On Wed, Nov 20, 2013 at 10:35 AM, Emina Torlak <emina at eecs.berkeley.edu>wrote:
> I believe Robby's solution will work. It's basically similar to what I
> had in mind, but I was hoping I'd be able to avoid it :)
>
> The crux of the issue is the need for unique identifiers for variable
> locations. I also track updates to vectors and structs, for example, and
> this is easy precisely because I can use their identities to compute the
> "location" of the update. So, boxing values in "raw" variables will have
> the same effect.
>
> In terms of implementation, though, it'll be trickier. As far as I can
> tell, this approach involves whole-module analysis and transformation:
>
> * Expand the module completely.
> * Find all uses of set! and collect their targets.
> * Rewrite the def and all uses of target variables to perform auto boxing
> and unboxing.
>
> If there are tricks/constructs that I should use for the above steps, I'd
> love to hear them. Or, of course, if there is some way to obtain variable
> location identifiers from the runtime, that would be great to know as well.
>
> Emina
>
>
>
>
>
> On Wed, Nov 20, 2013 at 5:19 AM, Robby Findler <
> robby at eecs.northwestern.edu> wrote:
>
>> I didn't try it, but you it might work to use local-expand and then find
>> all the binding forms and then rewrite them to use boxes (or some other
>> source of uniqueness you might have around).
>>
>> Robby
>>
>>
>> On Wed, Nov 20, 2013 at 12:53 AM, Emina Torlak <emina at eecs.berkeley.edu>wrote:
>>
>>> This is how my solution currently works, but unfortunately, it's not
>>> quite right. Here is a small example that demonstrates why, assuming the
>>> implementation based on free-id-table:
>>>
>>> (define (cell init)
>>> (let ([x init])
>>> (case-lambda
>>> [() x]
>>> [(v) (set! x v)])))
>>>
>>> (define foo (cell 0))
>>> (define bar (cell 1))
>>>
>>> > (foo 2)
>>> > (bar 3)
>>> > (foo)
>>> 2
>>> > (bar)
>>> 3
>>> > (dict->list global)
>>> '((.#<syntax:18:17 x> . 3))
>>>
>>> In the above scenario, I need the global map to contain two bindings:
>>> one for the location of 'foo.x' and the other for the location of 'bar.x.'
>>>
>>>
>>> Emina
>>>
>>>
>>>
>>> On Tue, Nov 19, 2013 at 10:31 PM, Sam Tobin-Hochstadt <
>>> samth at cs.indiana.edu> wrote:
>>>
>>>> I think that just identifiers and `free-id-table`s should work here.
>>>> Here's your example:
>>>>
>>>> #lang racket
>>>>
>>>> (require syntax/id-table (only-in racket [set! #%set!]))
>>>>
>>>> (define global (make-free-id-table))
>>>>
>>>> (define-syntax-rule (location-of id) #'id)
>>>>
>>>> (define-syntax-rule (set! id expr)
>>>> (let ([v expr])
>>>> (dict-set! global (location-of id) v)
>>>> (#%set! id v)))
>>>>
>>>> > (define x 1)
>>>> > (set! x 2)
>>>> > (set! x 3)
>>>> > (for/list ([(k v) (in-dict global)]) (list k v))
>>>> '((.#<syntax:4:8 x> 3))
>>>>
>>>> Also at https://gist.github.com/samth/7558673
>>>>
>>>> Sam
>>>>
>>>> On Mon, Nov 18, 2013 at 2:43 PM, Emina Torlak <emina at eecs.berkeley.edu>
>>>> wrote:
>>>> > I'm using Racket to implement a language for which I need to track
>>>> state
>>>> > updates---in particular, variable mutation using set!. For example,
>>>> > consider this module definition:
>>>> >
>>>> > #lang racket
>>>> >
>>>> > (require (only-in racket [set! #%set!]))
>>>> >
>>>> > (define global (make-hash))
>>>> >
>>>> > (define-syntax-rule (location-of id)
>>>> > (#%variable-reference id)) ; doesn't quite do the right thing
>>>> >
>>>> > (define-syntax-rule (set! id expr)
>>>> > (let ([val expr])
>>>> > (hash-set! global (location-of id) val)
>>>> > (#%set! id val)))
>>>> >
>>>> > When I evaluate the following sequence of forms against the above
>>>> > definition, I would like the global hash map to contain just one
>>>> binding
>>>> > that maps the location for 'x' to the value 2. With the above
>>>> > implementation I get two map entries, since variable-reference
>>>> doesn't quite
>>>> > do what I hoped it did:
>>>> >
>>>> >> (define x 0)
>>>> >> (set! x 1)
>>>> >> (set! x 2)
>>>> >> x
>>>> > 2
>>>> >> global
>>>> > '#hash((#<variable-reference> . 1) (#<variable-reference> . 2))
>>>> >
>>>> > Is there another construct in Racket that I could use for this
>>>> purpose? If
>>>> > not, can something like this be implemented and how much work would it
>>>> > entail?
>>>> >
>>>> > I have a purely macro-based solution that works for the most part,
>>>> but it's
>>>> > fragile and there are corner cases for which it is just wrong. So,
>>>> before
>>>> > trying to fix that, I was wondering if there is a nicer way to solve
>>>> it by
>>>> > somehow getting handles for variable locations that are comparable
>>>> using eq?
>>>> > or equal?
>>>> >
>>>> > Thanks!
>>>> >
>>>> > Emina
>>>> >
>>>> >
>>>> > ____________________
>>>> > Racket Users list:
>>>> > http://lists.racket-lang.org/users
>>>> >
>>>>
>>>
>>>
>>> ____________________
>>> Racket Users list:
>>> http://lists.racket-lang.org/users
>>>
>>>
>>
>
> ____________________
> Racket Users list:
> http://lists.racket-lang.org/users
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20131120/b9220911/attachment-0001.html>