From: Justin Dubs
Subject: (lables ...) as a macro
Date: 
Message-ID: <2e262238.0304121515.21596f0f@posting.google.com>
Hey everyone,

Sorry about all the crap I gave everyone a while back about lisp
implementation.  I was a poor, confused fool.


Anyway, I currently have 'let' implemented as a macro where:

(let ((var-1 form-1) ... (var-n form-n)) body*)

is equivalent to

(funcall #'(lambda (var-1 ... var-n) body*) form-1 ... form-n)

This, of course, works fine.  But, now I need 'labels'.


If I'm not mistaken, here's how this stuff works (please correct me if
I have anything wrong):

With let and flet, the new bindings are introduced into a lexical
environment in which the body is evaluated.  Hence, the lambda analog
works great.

With let* and flet* the scope of a binding includes both the body and
the subsequent bindings.

In other words, in:
(let* ((var-1 form-1) ... (var-n form-n)) body*)
form-x may use any var-y, y < x.

So, a let* can easily be turned into a series of nested lets:

(let ((var-1 form-1))
  ...
    (let ((var-n form-n))
      body*)...)

But, CLHS lists let* as one of the special operators.  So, am I wrong
about this?

With labels, the scope of each binding includes all the bindings as
well as the body so that form-x may use any var-y even if y >= x.

So, assuming that I have that right, the question is how to do it. 
The closest I can get is the following:

(flet ((name-1 nil nil) ... (name-n nil nil))
  (setf (symbol-function 'name-1) (lambda params-1 body-1))
  ...
  (setf (symbol-function 'name-n) (lambda params-n body-n))
  body*)

This, of course, doesn't work as (setf (symbol-function ...)) sets the
global function rather than the local function.  And, there is no
mention that I've been able to find in the CLHS of an equivalent of
symbol-function for local functions.  So, it seems that this can't be
done.

So, must labels be implemented as a special operator?  It is listed as
one in CLHS, but then so is let*.

Thanks for any help you can give me.

Justin Dubs

From: Kalle Olavi Niemitalo
Subject: Re: (lables ...) as a macro
Date: 
Message-ID: <87u1d2j40r.fsf@Astalo.kon.iki.fi>
······@eos.ncsu.edu (Justin Dubs) writes:

> With let and flet, the new bindings are introduced into a lexical
> environment in which the body is evaluated.  Hence, the lambda analog
> works great.

Have you implemented FLET as a macro?  I'd like to see that.

> With let* and flet* the scope of a binding includes both the body and
> the subsequent bindings.

CL doesn't have FLET*.

> So, a let* can easily be turned into a series of nested lets:
> 
> (let ((var-1 form-1))
>   ...
>     (let ((var-n form-n))
>       body*)...)

If the body begins with a bound declaration such as

  (declare (special var-1 var-2))

then you also need to split this to separate declarations for
each variable and insert them in the appropriate places.

> But, CLHS lists let* as one of the special operators.  So, am I wrong
> about this?

3.1.2.1.2.2 Macro Forms: "An implementation is free to implement
a Common Lisp special operator as a macro."

Whether you can actually write such a macro depends on what
special operators you do have.

> This, of course, doesn't work as (setf (symbol-function ...)) sets the
> global function rather than the local function.  And, there is no
> mention that I've been able to find in the CLHS of an equivalent of
> symbol-function for local functions.

Common Lisp does not have that feature.  If you want to implement
it as an extension, this would be a logical syntax:

  (setf (function name-1) (lambda params-1 body-1))

This can make optimization somewhat more difficult, as there can
then be regions of code where the compiler does not know to which
function a symbol refers.  In the expansion of the LABELS macro,
the compiler could recognize that the functional value of the
symbol is unconditionally set to the same function (modulo
closures), and propagate that constant into the following forms.
Things get trickier if someone puts the SETF inside a conditional.
From: Justin Dubs
Subject: Re: (lables ...) as a macro
Date: 
Message-ID: <2e262238.0304130843.232e1c94@posting.google.com>
Kalle Olavi Niemitalo <···@iki.fi> wrote in message news:<··············@Astalo.kon.iki.fi>...
> ······@eos.ncsu.edu (Justin Dubs) writes:
> 
> > With let and flet, the new bindings are introduced into a lexical
> > environment in which the body is evaluated.  Hence, the lambda analog
> > works great.
> 
> Have you implemented FLET as a macro?  I'd like to see that.

Heh.  In a Common Lisp that would be tricky (read: impossible).  In my
languge I'm working with some ideas to introduce syntax into lambda
parameter lists, and hence into let, that would make this easier
(read: possible).

> 
> > With let* and flet* the scope of a binding includes both the body and
> > the subsequent bindings.
> 
> CL doesn't have FLET*.

Okay, thanks.  I was unaware of that.  I'll assume that if it did have
flet*, that's how it would work though.  :-)

> 
> > So, a let* can easily be turned into a series of nested lets:
> > 
> > (let ((var-1 form-1))
> >   ...
> >     (let ((var-n form-n))
> >       body*)...)
> 
> If the body begins with a bound declaration such as
> 
>   (declare (special var-1 var-2))
> 
> then you also need to split this to separate declarations for
> each variable and insert them in the appropriate places.

Good point.  As I don't have "declarations" yet, I hadn't considered
that.  Thanks.  Still, let* can theoretically be done as a macro it
seems.

> 
> > But, CLHS lists let* as one of the special operators.  So, am I wrong
> > about this?
> 
> 3.1.2.1.2.2 Macro Forms: "An implementation is free to implement
> a Common Lisp special operator as a macro."
> 
> Whether you can actually write such a macro depends on what
> special operators you do have.

Thanks again.  I didn't realize CLHS said that.

> 
> > This, of course, doesn't work as (setf (symbol-function ...)) sets the
> > global function rather than the local function.  And, there is no
> > mention that I've been able to find in the CLHS of an equivalent of
> > symbol-function for local functions.
> 
> Common Lisp does not have that feature.  If you want to implement
> it as an extension, this would be a logical syntax:
> 
>   (setf (function name-1) (lambda params-1 body-1))
> 
> This can make optimization somewhat more difficult, as there can
> then be regions of code where the compiler does not know to which
> function a symbol refers.  In the expansion of the LABELS macro,
> the compiler could recognize that the functional value of the
> symbol is unconditionally set to the same function (modulo
> closures), and propagate that constant into the following forms.
> Things get trickier if someone puts the SETF inside a conditional.

At this very experimental point in my language's design, optimization
is not one of my big concerns.  :-).  However, yes, you are correct
about all of that.  I'll likely just give up and implement labels as a
rather simple special operator.

Thanks again for the response,

Justin Dubs
From: Fred Gilham
Subject: Re: (lables ...) as a macro
Date: 
Message-ID: <u7n0iunqsr.fsf@snapdragon.csl.sri.com>
> > > With let* and flet* the scope of a binding includes both the
> > > body and the subsequent bindings.
> > 
> > CL doesn't have FLET*.
> 
> Okay, thanks.  I was unaware of that.  I'll assume that if it did
> have flet*, that's how it would work though.  :-)

I'm confused.  What is the conceptual difference here between labels
and flet*?  Is it that labels creates a "flat" scope where everything
is visible, but flet* would create a series of nested scopes?

-- 
Fred Gilham                                        ······@csl.sri.com
An ABC camera crew interviewed Hillary Clinton in the Bahamas, where
she was sunning herself on a flat rock to keep her body temperature
up. "Cookies," she said, eyeing the cameras. "Children." -- Fred Reed
From: Justin Dubs
Subject: Re: (lables ...) as a macro
Date: 
Message-ID: <2e262238.0304131958.693e188b@posting.google.com>
Fred Gilham <······@snapdragon.csl.sri.com> wrote in message news:<··············@snapdragon.csl.sri.com>...
> > > > With let* and flet* the scope of a binding includes both the
> > > > body and the subsequent bindings.
> > > 
> > > CL doesn't have FLET*.
> > 
> > Okay, thanks.  I was unaware of that.  I'll assume that if it did
> > have flet*, that's how it would work though.  :-)
> 
> I'm confused.  What is the conceptual difference here between labels
> and flet*?  Is it that labels creates a "flat" scope where everything
> is visible, but flet* would create a series of nested scopes?

Well, first off, flet* doesn't exist.  However, if flet* were to work
like let*, then it would be like you indicated.  It would be
conceptually similar to a series of nested scopes.

(flet* ((fn1 (x) x)
        (fn2 (x) (fn1 1)))
  (fn2 1))

Is roughly the same as

(flet ((fn1 (x) x))
  (flet ((fn2 (x) (fn1 x)))
    (fn2 1)))

In fact with flet, the binding for fn1 doesn't exist until inside the
body of the flet.  So, the function fn1 is visible to fn2, but not to
fn1 itself.  So, functions defined with a flet or a hypothetical flet*
can not be recursive.

With labels however, magic happens.  All the bindings are introduced
simultaneously.  And all are visible within eachothers bodies.  So,
functions declared with labels can not only be recursive, they can be
mutually recursive.

Hope that helps,

Justin Dubs
From: sv0f
Subject: Re: (lables ...) as a macro
Date: 
Message-ID: <none-2A59F7.09573114042003@news.vanderbilt.edu>
In article <····························@posting.google.com>,
 ······@eos.ncsu.edu (Justin Dubs) wrote:

>Anyway, I currently have 'let' implemented as a macro where:
>
>(let ((var-1 form-1) ... (var-n form-n)) body*)
>
>is equivalent to
>
>(funcall #'(lambda (var-1 ... var-n) body*) form-1 ... form-n)

Just write:

     ((lambda (var-1 ... var-n) body*) form-1 ... form-n)
From: Kent M Pitman
Subject: Re: (lables ...) as a macro
Date: 
Message-ID: <sfwptnpqf3r.fsf@shell01.TheWorld.com>
sv0f <····@vanderbilt.edu> writes:

> In article <····························@posting.google.com>,
>  ······@eos.ncsu.edu (Justin Dubs) wrote:
> 
> >Anyway, I currently have 'let' implemented as a macro where:
> >
> >(let ((var-1 form-1) ... (var-n form-n)) body*)
> >
> >is equivalent to
> >
> >(funcall #'(lambda (var-1 ... var-n) body*) form-1 ... form-n)
> 
> Just write:
> 
>      ((lambda (var-1 ... var-n) body*) form-1 ... form-n)

Not having been reading the whole thread, I don't know the context for
this, but LET is not equivalent to the expanded lambda combination
shown above (nor to the more clumsy FUNCALL form).

Consider:

 (let ((x (- x y)))
   (declare (fixnum x y))
   (- x y))

which is correctly rendered as

 ((lambda (x)
    (declare (fixnum x y))
    (- x y))
  (locally (declare (fixnum y)) ; NOTE: Not (fixnum x y)
    (- x y)))

Note that it is not correct to do either:

 ((lambda (x)
    (declare (fixnum x y))
    (- x y))
  (locally (declare (fixnum x y))
    (- x y)))

NOR

 ((lambda (x)
    (declare (fixnum x y))
    (- x y))
  (- x y))

NOR

((lambda (x)
    (- x y))
  (locally (declare (fixnum x y))
    (- x y)))

This is because X in the original LET is a bound declaration.
Bound declarations affect only the scope of their binding.
Y in the original LET is a free declaration.  Free declarations
affect the entire text of their containing form.
From: Alexey Dejneka
Subject: Re: (lables ...) as a macro
Date: 
Message-ID: <m34r512err.fsf@comail.ru>
Hello,

Kent M Pitman <······@world.std.com> writes:

> Consider:
> 
>  (let ((x (- x y)))
>    (declare (fixnum x y))
>    (- x y))
> 
> which is correctly rendered as
> 
>  ((lambda (x)
>     (declare (fixnum x y))
>     (- x y))
>   (locally (declare (fixnum y)) ; NOTE: Not (fixnum x y)
>     (- x y)))
> 
> Note that it is not correct to do either:
[...]
> NOR
> 
>  ((lambda (x)
>     (declare (fixnum x y))
>     (- x y))
>   (- x y))
[...]
> Y in the original LET is a free declaration.  Free declarations
> affect the entire text of their containing form.

Erm. CLHS 3.3.4:

  Unless explicitly stated otherwise, the scope of a free declaration
  includes only the body subforms of the form at whose head it
  appears, and no other subforms. The scope of free declarations
  specifically does not include initialization forms for bindings
  established by the form containing the declarations.

Seems like ((lambda (x) (declare (fixnum x y)) (- x y)) (- x y)) is the
correct translation.

-- 
Regards,
Alexey Dejneka

"<Zhivago> mutants tend to turn evil after a while, and go around
eating people's brains." -- #lisp
From: Kent M Pitman
Subject: Re: (lables ...) as a macro
Date: 
Message-ID: <sfwbrz8anid.fsf@shell01.TheWorld.com>
Alexey Dejneka <········@comail.ru> writes:

> Kent M Pitman <······@world.std.com> writes:
> 
> > Consider:
> > 
> >  (let ((x (- x y)))
> >    (declare (fixnum x y))
> >    (- x y))
> > 
> > which is correctly rendered as
> > ...
>
> Erm. CLHS 3.3.4:
> 
>   Unless explicitly stated otherwise, the scope of a free declaration
>   includes only the body subforms of the form at whose head it
>   appears, and no other subforms. The scope of free declarations
>   specifically does not include initialization forms for bindings
>   established by the form containing the declarations.
> 
> Seems like ((lambda (x) (declare (fixnum x y)) (- x y)) (- x y)) is the
> correct translation.

Oh, hmm, sigh... Yeah, serves me right for not checking.  Thanks for
catching this!  This stuff was resolved bizzarely in a flurry of ruffled
feathers and spilled blood, and I don't think anyone was totally happy
with the result--certainly not I.  But I guess I was misremembering the
specifics of the bizarreness that resulted. *blush*
From: Joe Marshall
Subject: Re: (lables ...) as a macro
Date: 
Message-ID: <wuhxcgbe.fsf@ccs.neu.edu>
······@eos.ncsu.edu (Justin Dubs) writes:

> So, must labels be implemented as a special operator?  It is listed as
> one in CLHS, but then so is let*.

It is *usually* implemented as a special operator, but you *could* use
an n-ary Y combinator if you were a masochist.
From: Michael Hudson
Subject: Re: (lables ...) as a macro
Date: 
Message-ID: <7h3wuhxrv7a.fsf@pc150.maths.bris.ac.uk>
······@eos.ncsu.edu (Justin Dubs) writes:

> So, a let* can easily be turned into a series of nested lets:

Not quite: declarations.

There are situations where this makes a difference, but I can't
remember them off hand... presumably something to do with (declare
(special ...)).

Cheers,
M.

-- 
  Enlightenment is probably antithetical to impatience.
                                        -- Erik Naggum, comp.lang.lisp