> > > foo > > |b| > b := 3. > ^ [ |a | a :=2. a] > > In my stupid lisp implementation an environment is represented by bindings > and closure points to their own environment > so > [ |a | a :=2. a] > points to > (b.3) (toplevel) (and not top-level) > > and for closure execution we just added temporaly a binding for a to the > closure environment. > eval a:=2. a in (a) (b.3) (toplevel) > > This is the wrong example.
I understand your example below and the fact that closure environment is
allocated on the heap via an array to be independent of the activation context
but I do not get why consing the local environment to be one current one is
wrong.
(define (%apply proc largs)
(cond ((%primitive? proc) (%apply-internal proc largs))
((%closure? proc) (%apply-closure proc largs))
(else (error "Bad ! Un-apply-able object !" proc))))
(define (%apply-closure proc largs)
;; apply a closure: evaluate proc body in
;; extended the closure environment with
;; proc arguments and largs
(%eval (%closure-body proc)
(%extend-env (%closure-args proc) largs (%closure-env proc))))
(define (%eval-lambda expr env)
;; lambda in Scheme captures the environment at compile time
;; expr = ((x) (+ x 2))
(%make-closure (car expr) (cadr expr) env))
> You need to consider how to implement this example:
>
> Object subclass: #AbstractSuperclass
>
> AbstractSuperclass>>computeV
> | v |
> v := 0.
> self maybeCapture: [v := v + 1. v].
> ^self maybeBlock: v
>
> AbstractSuperclass subclass: #CaptureBlock
> instanceVariableNames: 'block'
>
> CaptureBlock>>maybeCapture: aBlock
> block := aBlock
>
> CaptureBlock>>maybeBlock: value
> ^block
>
> AbstractSubclass subclass: #DontCaptureBlock
>
> DontCaptureBlock>>maybeCapture: aBlock
>
> DontCaptureBlock>>maybeBlock: value
> ^value
>
>
> Then
> | thingOne thingTwo |
> thingOne := CaptureBlock computeV.
> thingTwo := DontCaptureBlock computeV.
> (1 to: 10) collect: [:ignore| { thingOne value. thingTwo value }]
>
> should answer
> #((1 0) (2 0) (3 0) ... (10 0))
if 0 value returns 0? yes. (it confused me for a while).
> right? So where does the l-value for v in computeV live? Iy must be an
> l-value since it is assigned to in the block in computeV. It must outlive
> the activation of computeV since CaptureBlock>maybeCapture: captures the
> block and CaptureBlock>>maybeBlock: answers it and the doit evaluates it. If
> it lives on the stack of the activation of computeV then there is no problem
> in a Context VM, but in a VM that maps activations to stack frames something
> special (and slow) has to happen when returning from computeV. However, if
> the l-value lives in a separate Array (as it does in my VisualWorks and
> Squeak closure implementations, and as happens in some Lisp implementations),
> nothing special has to happen. The block refers to the Array, *not* to the
> activation of computeV.
>
> Make sense now?
Yes you allocate on the heap closure binding to be orthogonal to activation
context.
limitedScheme.scm
Description: Binary data
I will reread your blog now. Stef
