Re: How to implement lexical closures?

George Neuner <gneuner2@comcast.net>
Sun, 09 May 2010 19:31:16 -0400

          From comp.compilers

Related articles
How to implement lexical closures? grom358@gmail.com (grom) (2010-05-06)
Re: How to implement lexical closures? sleepdev@gmail.com (andy johnson) (2010-05-09)
Re: How to implement lexical closures? gneuner2@comcast.net (George Neuner) (2010-05-09)
Re: How to implement lexical closures? cr88192@hotmail.com (BGB / cr88192) (2010-05-09)
Re: How to implement lexical closures? torbenm@diku.dk (2010-05-10)
Re: How to implement lexical closures? grom358@gmail.com (grom) (2010-05-11)
Re: How to implement lexical closures? cr88192@hotmail.com (BGB / cr88192) (2010-05-12)
Re: How to implement lexical closures? gene.ressler@gmail.com (Gene) (2010-05-12)
Re: How to implement lexical closures? gah@ugcs.caltech.edu (glen herrmannsfeldt) (2010-05-13)
[7 later articles]
| List of all articles for this month |

From: George Neuner <gneuner2@comcast.net>
Newsgroups: comp.compilers
Date: Sun, 09 May 2010 19:31:16 -0400
Organization: A noiseless patient Spider
References: 10-05-031
Keywords: storage
Posted-Date: 10 May 2010 01:20:58 EDT

On Thu, 6 May 2010 21:22:21 -0700 (PDT), grom <grom358@gmail.com>
wrote:


>I'm working on a toy interpreter (http://code.google.com/p/zemscript/)
>and trying to implement lexical closures (http://code.google.com/p/
>zemscript/source/browse/#svn/branches/lexical_scope) .
>
>However since it copies the symbol table the following does *not*
>work:
>create = function() {
> x = 0;
> return {
> "get" : function() { return x; },
> "set" : function(v) { x = v; }
> };
>};
>
>o = create();
>o["set"](42);
>println(o["get"]()); // Should print 42
>
>What I can't work out is how I can get the second example to work
>without breaking the first example.
>
>Ant build file: http://pastebin.com/qDaZethE


I don't know the semantics of you language and so the intent of the
code above is not exactly clear. In particular, I'm not sure whether
'o' represents a function or an object with methods.


Regardless, you need to create 2 separate closures - one for 'get' and
one for 'set', closing both over the same variable x.


In Scheme I'd approximate (what I believe to be) the functionality of
your code with something like:


(define create
    (lambda ()
        (let ((x 42))
            (let ((funcs (list
                                        (cons 'get (lambda () x))
                                        (cons 'set (lambda (v) (set! x v)))
                                        )))
                (lambda (cmd . arg)
                    (let (if (assoc cmd funcs)))
                        (if f
                                (if (eq? arg '())
                                        ((cdr f))
                                        ((cdr f) (car arg)) )
                                (error "undefined function")
                      )))
                ))))


(define bar (create))
(define baz (create))


  > (bar 'get)
  42
  > (baz 'get)
  42
  > (bar 'set "hi")
  > (bar 'get)
  "hi"
  > (baz 'get)
  42
  > (baz 'set)
  #<procedure>: expects 1 argument, given 0
  > (baz 'quit)
  undefined function




In case you can't decipher the Scheme, the function 'create' creates
an environment containing the variable 'x', creates a second
environment containing 2 anonymous functions closed over 'x' and an
association list pairing the symbols 'get and 'set to their respective
functions, and creates and returns an anonymous function in the root
environment, closed over the second environment in which it looks up
its first argument and applies the associated function passing its
second argument.


The [paraphrased] environment picture looks like:


  +-------------------------------------------------------+
  | #proc3: (cmd,arg) {if (cmd in funcs) funcs[cmd](arg)} |
  | create: () { return #proc3 } |
  | bar : #proc3 |
  | baz : #proc3 |
  +-------------------------------------------------------+
                                                                  |
      +------+ |
      | x:42 | <--+ |
      +------+ | |
                              | V
          +---------------------------------------------+
          | #proc1: () { return x } |
          | #proc2: (v) { x = v } |
          | funcs : list(('get, #proc1),('set, #proc2)) |
          +---------------------------------------------+






What you need to do for your language depends on its semantics, but
generally you don't want to copy environments[*], but rather create
new ones as necessary, bind their variables, and chain them together
according to the lexical structure of the language. Closures then
link functions to the tree of environments that the functions require
to work.
[*] except maybe as a 1st step to evaluate untrusted code.




Hope this helps.
George



Post a followup to this message

Return to the comp.compilers page.
Search the comp.compilers archives again.