[plt-scheme] Re: adventure game code ported to PLT 4 ?

From: Felix Klock's PLT scheme proxy (pltscheme at pnkfx.org)
Date: Mon Oct 20 18:13:39 EDT 2008

On Oct 20, 2008, at 8:45 AM, Felix Klock's PLT scheme proxy wrote:

>
> On Oct 20, 2008, at 4:12 AM, Noel Welsh wrote:
>
>> On Mon, Oct 20, 2008 at 3:24 AM, Fred G. Martin <fredm at cs.uml.edu>  
>> wrote:
>>> Well, this was actually pretty easy, with one exception... the  
>>> "show" procedure.
>>>
>>> It seems to use MIT Scheme-specific features (environment->package,
>>> fluid-let, environment-bindings)... Is this portable to PLT?
>>
>> Look at namespaces and parameters for the PLT equivalent (well,  
>> nearest match).
>
> Its probably going to need more than that; it looks to me like that  
> selectors like procedure-environment are extracting the lexical  
> environment that procedure objects are closed over.  Namespaces  
> model global environments; I do not know if PLT has anything for  
> reifying the local bindings.
>
> However, it also looks to me like the show procedure may only be  
> there for, mmm, "debugging" purposes?  (Or at least for easy  
> interactive inspection of "object" structure at the REPL; the point  
> is, show is not called from game.scm or world.scm...)

I was inspired this morning to try to hack up an approximation of  
this.  After some messing around (trying to do the hard stuff myself),  
SamTH pointed me at the key.  (I asked him "how do I get the free  
variables of locally expanded code" and he said "Use free-vars from  
syntax/free-vars; look in the Help Desk.")

Fred: in particular, you may be able to adapt this to get similar  
inspection routines of the "objects" in the Adventure Game code,  
although I do not immediately see a "good" way to extract the implicit  
environment frame structure.

Enjoy!  (Sorry that the documentation is longer than the code!)

-Felix


#lang scheme

#|
    This code is a big ol' hack to emulate MIT Scheme's ability
    to inspect the lexical environment of procedure objects.

    One big distinction is that it only allows you to
    inspect the free lexical variables of procedures defined
    via the LAMBDA/INSPECTABLE form (defined below); you cannot
    use it to inspect arbitrary closures generated from other
    code.  (Felix does not think PLT offers an interface to
    get at that information, justifiably so.)

    Another big distinction between this and the environment
    objects of MIT Scheme is that this currently does not tell
    you anything about the frame structure; all of the free
    (but lexically bound) variables of a lambda/inspectable
    expression are given equal treatment, as opposed to giving
    the client the ability to observe how many frames up a
    free variable is bound.

    Also, on a related note, only referenced variables of
    a lambda/inspectable expression are captured, *not*
    all "available" variables.  E.g. x is not free in:
      (lambda () 3)
    so the implicit environment [x := 5] is not captured by
      ((lambda (x) (lambda/inspectable () 3)) 5)
    even though it is captured by
      ((lambda (x) (lambda/inspectable () x)) 5)

    Finally, this code exposes the free variables as symbols
    rather than identifier objects, with the obvious ambiguity
    problems.  Sorry; I went with "Worse is Better" here.

    Example usage:

    > (define g (lambda/inspectable (x) (lambda/inspectable (y) (+ x  
y))))
    > (define add3 (g 3))
    > (define add7 (g 7))
    > (add3 10)
    13
    > (add7 10)
    17
    > (procedure? g)
    #t
    > (procedure? add3)
    #t
    > (annotated-proc? g)
    #t
    > (annotated-proc-free-vars g)
    ()
    > (annotated-proc-free-vars add3)
    (x)
    > (annotated-proc-free-vars add7)
    (x)
    > ((annotated-proc-var-ref add3) 'x)
    3
    > ((annotated-proc-var-ref add7) 'x)
    7
|#

(require (for-syntax syntax/free-vars))

(define-struct annotated-proc (base free-vars var-ref)
   #:property prop:procedure (struct-field-index base))

(define-syntax lambda/inspectable
   (lambda (stx)
     (syntax-case stx ()
       ((_ ARGL BODY ...)
        (let* ((free-vars (lambda (stx)
                            (call-with-values
                             (lambda ()
                               (syntax-local-expand-expression stx))
                             (lambda (expanded opaque)
                              (free-vars expanded)))))
               (fv (free-vars #'(lambda ARGL BODY ...)))
               (var-symbols (map syntax->datum fv))
               (var-syntaxs fv))
          #`(let* ((clos (lambda ARGL BODY ...))
                   (names (quote #,var-symbols))
                   (entries
                    (list #,@(map (lambda (var-sym var-stx)
                                    #`(list (quote #,var-sym)
                                            (lambda () #,var-stx)))
                                  var-symbols
                                  var-syntaxs))))
              (make-annotated-proc clos
                                   names
                                   (lambda (var)
                                     ((cadr (assoc var  
entries)))))))))))


Posted on the users mailing list.