From: charlieb
Subject: Question about let
Date: 
Message-ID: <1014577540.21538.0@eurus.uk.clara.net>
I was working my way through a certain lisp book when I came upon the
following piece of code (with longer variable names and balanced brackets)

(defun powers-of-two ()
  (let ((last-power 1)
        (next-value #'(lambda () (setq last-power (* last-power 2))))
        (reset-value #'(lambda () (setq last-power 1))))
    #'(lambda (&optional accessor)
     (cond
      ((null accessor) next-value))))
      ((eq accessor 'reset) reset-value))))))))

I dutifully typed this into GCL and low and behold the two lambda
expressions (*-value) cannot see the last-power variable. Why is this? Is
the book wrong? Is GCL wrong? What is going on?

BTW I rewrote it as below which works but I'm still puzzled

(defun powers-of-two ()
  (let ((last-power 1))
    #'(lambda (&optional accessor)
     (cond
      ((null accessor) #'(lambda () (setf last-power (* last-power 2))))
  ((eq accessor 'reset) #'(lambda () (setf last-power 1)))))))))


Cheers
Charlie.

From: Bulent Murtezaoglu
Subject: Re: Question about let
Date: 
Message-ID: <874rk6hdo1.fsf@nkapi.internal>
Let binds variables in 'parallel.'  Let* binds them sequentially
(see the hyperpec:    
http://www.xanalys.com/software_tools/reference/HyperSpec/Body/s_let_l.htm )

GCL is a bit behind in implementing ANSI CL, but it should get let/let* 
right.

I don't know what that code is supposed to do exactly and why it is 
written that way but here's what happens in CMUCL with let* :

* (defun powers-of-two ()
  (let* ((last-power 1)
	 (next-value #'(lambda () (setq last-power (* last-power 2))))
	 (reset-value #'(lambda () (setq last-power 1))))
    #'(lambda (&optional accessor)
	(cond
	 ((null accessor) next-value)
	 ((eq accessor 'reset) reset-value)))))

POWERS-OF-TWO
* (setq foo (powers-of-two))
#<Interpreted Function "LAMBDA NIL" {48948581}>
* (setq bar (funcall foo))
#<Interpreted Function "LAMBDA NIL" {489484D1}>
* (setq baz (funcall foo 'reset))
#<Interpreted Function "LAMBDA NIL" {48948529}>
* (funcall bar)
2
* (funcall bar)
4
* (funcall baz)
1
* (funcall bar)
2
* 

hope this helps,

BM
From: Kaz Kylheku
Subject: Re: Question about let
Date: 
Message-ID: <onbe8.120935$A44.7415532@news2.calgary.shaw.ca>
In article <··················@eurus.uk.clara.net>, charlieb wrote:
>I was working my way through a certain lisp book when I came upon the
>following piece of code (with longer variable names and balanced brackets)
>
>(defun powers-of-two ()
>  (let ((last-power 1)
>        (next-value #'(lambda () (setq last-power (* last-power 2))))
>        (reset-value #'(lambda () (setq last-power 1))))
>    #'(lambda (&optional accessor)
>     (cond
>      ((null accessor) next-value))))
>      ((eq accessor 'reset) reset-value))))))))
>
>I dutifully typed this into GCL and low and behold the two lambda
>expressions (*-value) cannot see the last-power variable. Why is this? Is
>the book wrong? Is GCL wrong? What is going on?

Yes, the book is wrong. If you want the lambda expressions to see the
variable, you have to use let* rather than let, or use nested lets.

The let constructs evaluates all of the variable initialization forms
in left to right order, and *then* establishes the variable bindings.
Thus the bindings are not yet visible to the init forms.

By contrast, the let* form calls each init form and establishes
the binding right away, in left to right order; in effect, it's
a condensed way of writing a bunch of nested lets. E.g.

  (let ((a x)) 
    (let ((b (+1 a))) 
      (let ((c (+1 b))) 
        ...)))

can be rewritten:

  (let* ((a x) 
         (b (+1 a)) 
         (c (+1 b)))
    ...)

On a different note, you should be aware that GCL isn't a complete,
conforming implementation of Common Lisp.

-- 
Meta-CVS: version control with directory structure versioning over top of CVS.
http://users.footprints.net/~kaz/mcvs.html
From: Kent M Pitman
Subject: Re: Question about let
Date: 
Message-ID: <sfwg03qwt7a.fsf@shell01.TheWorld.com>
"charlieb" <·······@freeuk.com> writes:

> I was working my way through a certain lisp book when I came upon the
> following piece of code (with longer variable names and balanced brackets)
> 
> (defun powers-of-two ()
>   (let ((last-power 1)
>         (next-value #'(lambda () (setq last-power (* last-power 2))))
>         (reset-value #'(lambda () (setq last-power 1))))
>     #'(lambda (&optional accessor)
>      (cond
>       ((null accessor) next-value))))
>       ((eq accessor 'reset) reset-value))))))))
> 
> I dutifully typed this into GCL and low and behold the two lambda
> expressions (*-value) cannot see the last-power variable. 

Funny you should mention *.  For unrelated reasons, you want LET*, not LET.
LET* causes bindings to appear from left to right, in order, in time to be
usable in the init form for the subsequent binding.  This is called
"sequential binding". Nesting two LETs each with one variable is the same
as using LET* with two variables.    That is,
 (let* ((a (init-a))
        (b (init-b)))
   ...)
is the same as
 (let ((a (init-a)))
   (let ((b (init-b)))
     ...))

The model for LET, in turn, is to evaluate all the inits from left to right,
in order, _before_ establishing any bindings for the named variables in 
that let.  This is called "parallel bindings" (no relation to multitasking).
Parallel binding is more complicated to describe in terms of nesting LETs
but what you have written above is effectively the same as:

 (defun powers-of-two ()
   (let ((last-power.init 1))
     (let ((next-value.init #'(lambda () (setq last-power (* last-power 2)))))
       (let ((reset-value.init #'(lambda () (setq last-power 1))))
         (let ((last-power last-power.init))
           (let ((next-value next-value.init))
             (let ((reset-value reset-value.init))
               #'(lambda (&optional accessor)
                   (cond ((null accessor) next-value))))
                         ((eq accessor 'reset) reset-value)))))))


Hopefully you can see here that because you are still evaluating the binding
forms, the value of last-power is not yet available.

> Why is this? Is
> the book wrong? Is GCL wrong? What is going on?

Don't know what book you're using and whether you're just overlooking a "*"
on the LET in the book, so don't want to say it's wrong without looking.
But if you transcribed it correctly above, then the book is wrong.  If  you
goofed in the transcribing, then you're at fault.  The implementation is
right in saying last-power is not available.

> BTW I rewrote it as below which works but I'm still puzzled
> 
> (defun powers-of-two ()
>   (let ((last-power 1))
>     #'(lambda (&optional accessor)
>      (cond
>       ((null accessor) #'(lambda () (setf last-power (* last-power 2))))
>       ((eq accessor 'reset) #'(lambda () (setf last-power 1)))))))))

Yes, now you're inside the LET and the binding has been established.  It
would also have worked to do:

 (let ((last-power 1))
   (let ((next-value #'(lambda () (setf last-power (* last-power 2))))
         (reset-value #'(lambda () (setf last-power 1))))
     ...))
From: charlieb
Subject: Re: Question about let
Date: 
Message-ID: <1014584750.4916.0@eurus.uk.clara.net>
"Kent M Pitman" <······@world.std.com> wrote in message
····················@shell01.TheWorld.com...
> "charlieb" <·······@freeuk.com> writes:
>
> > Why is this? Is
> > the book wrong? Is GCL wrong? What is going on?
>
> Don't know what book you're using and whether you're just overlooking a
"*"
> on the LET in the book, so don't want to say it's wrong without looking.
> But if you transcribed it correctly above, then the book is wrong.  If
you
> goofed in the transcribing, then you're at fault.  The implementation is
> right in saying last-power is not available.
>

Ah ha, thank-you all. The book BTW is LISP 3rd Edition by P.H. Winston and
B.K.P. Horn and the example is on page 223 at the bottom.

Thanks
Charlieb
From: Jim Bushnell
Subject: Re: Question about let
Date: 
Message-ID: <vPce8.62576$Ig2.16977570@news1.elcjn1.sdca.home.com>
"charlieb" <·······@freeuk.com> wrote in message
·······················@eurus.uk.clara.net...
> I was working my way through a certain lisp book when I came upon the
> following piece of code (with longer variable names and balanced brackets)
>
> (defun powers-of-two ()
>   (let ((last-power 1)
>         (next-value #'(lambda () (setq last-power (* last-power 2))))
>         (reset-value #'(lambda () (setq last-power 1))))
>     #'(lambda (&optional accessor)
>      (cond
>       ((null accessor) next-value))))
>       ((eq accessor 'reset) reset-value))))))))
>
> I dutifully typed this into GCL and low and behold the two lambda
> expressions (*-value) cannot see the last-power variable. Why is this? Is
> the book wrong? Is GCL wrong? What is going on?
>
> BTW I rewrote it as below which works but I'm still puzzled
>
> (defun powers-of-two ()
>   (let ((last-power 1))
>     #'(lambda (&optional accessor)
>      (cond
>       ((null accessor) #'(lambda () (setf last-power (* last-power 2))))
>   ((eq accessor 'reset) #'(lambda () (setf last-power 1)))))))))
>
>
> Cheers
> Charlie.
>
>
Look up let and let* in the Hyperspec.

Jim Bushnell