Adding closures to a shallow-binding interpreter.
I have a shallow-binding interpreter, which has no lexical closure.
My attempts to implement (function ) have been only partially succesful,
am I right in assuming that this is impossible?
So far my best attempt has been the following:
(defmacro my-function (fn)
`'(lambda (&rest f-args)
((lambdaq ,(bound-oblist)
(apply fn f-args))
,@(mapcar 'eval (bound-oblist)))))
I should explain that in in the interpreter:
lambdaq forms do not evaluate their arguments,
(bound-oblist) is a function that returns a list of all the symbols
with bound values.
symbols have only one value which can be a function
; Simple test case:
(setq free 67)
(setq my-test (my-function (lambda (a) (cons a free))))
(print (my-test 12))
(setq free 88)
(print (my-test 12))
; produces:
; (12 . 67)
; (12 . 67)
The simple cases work ok, however the following :
(setq free 67)
(setq my-test2 (my-function (lambda () (print free)(setq free 4))))
(my-test2)
(my-test2)
produces:
; 67
; 67
Where CLtL2 would want it to produce 67 4.
It is obvious why it cannot, but is there any way to do it?
Thanks in advance,
Bill
--
Bill Birch | ·······@uk03.bull.co.uk
Bull Info. Sys. Ltd. | Bull Tel: 773 4367
Maxted Road, | Bull Mail: HM14 UK03
Hemel Hempstead, | Tel: +44 442 884367
HERTS, HP2 7DZ, U.K. | Fax: +44 442 884570
Aviate, Navigate, Communicate...
From: ·······@cc.helsinki.fi
Subject: Re: Adding FUNCTION to a shallow-binding interp.
Date:
Message-ID: <1992Nov12.144242.1@cc.helsinki.fi>
In article <·····················@uk03.bull.co.uk>, ······@hemel.bull.co.uk (Bill Birch) writes:
> I have a shallow-binding interpreter, which has no lexical closure.
> My attempts to implement (function ) have been only partially succesful,
> am I right in assuming that this is impossible?
You're right: it is impossible with the tools you're using. Basically,
since the same name should have different bindings in each different
scope, you need a distinct storage location for each, and SETQ of a
local variable has to know about them. A good test case is:
(defun two-functions(&aux x)
(list #'(lambda () x) #'(lambda (y) (setq x y))))
Each call of TWO-FUNCTIONS has to create a new binding of X, which the
two functions share.
The standard solution for shallow-binding systems is external value
cells: a closed-over variable has a pointer to an external value cell,
which is a dynamically allocated object that holds the value of the
variable in that scope; each closure has a list of variables it closes
over and their external value cells. For example, TWO-FUNCTIONS might
return something like this:
(#<closure (lambda () x) ((x . #1=#<external-value-cell nil))>
#<closure (lambda (y) (setq x y)) ((x . #1#))>)
with new closures containing a new external value cell for each
invocation. There are quite a few pitfalls in getting closures just
right, good luck!
___
Pekka P. Pirinen ·············@helsinki.fi
Lisp implementor