> 
> 
> 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. 

Attachment: limitedScheme.scm
Description: Binary data


I will reread your blog now.

Stef

Reply via email to