From: Aaron Sloman
Subject: Re: nested function definitions and lexical binding
Date: 
Message-ID: <492@cvaxa.sussex.ac.uk>
>From: ·····@faculty.cs.ubc.ca (Vincent Manis)
>Message-ID: <····@ubc-cs.UUCP>
>Date: 21 Jun 88 19:59:42 GMT
> .......
>I think it's a mistake to define an internal definition to change the
>*global* value of the function cell: this is almost always not what
>one would expect, given lexical binding. Either don't provide it at
>all (as CL doesn't) or give it the same semantics as in Scheme.

I absolutely agree, except that the point is not restricted to lexical
binding, and "almost" should have been omitted.

Allowing properly nested function definitions is very useful and has
been used by the Pop community for some time.

Pop-11 allows properly nested definitions for both lexically and
dynamically scoped names of functions. E.g. the main interrupt handler
(whose name is dynamically scoped) is locally re-definable thus:

    define foo .....;
        define interrupt;
            <interrupt behaviour desired whilst foo is running>
        enddefine;

        <code for foo>
    enddefine;

Because it is a truly local definition, any normal or abnormal exit
from foo will re-set the global value of interrupt. Some procedures
running in the environment of foo may also locally redefine interrupt
to do something different again.

Similarly one can locally redefine the current error handler, the
current output character consumer used by all the standard printing
funcions, etc. etc. This facility has been generally available in all
Pop systems since around 1970 I think.

In Poplog Pop-11, lexically scoped local definitions allow safe use of
functions that are called from other locally defined functions given as
arguments to externally defined functions.

e.g. in Poplog Pop-11

   define foo .....
      define lconstant baz ...;   ;;; lconstant makes baz lexical and
         <code for baz>           ;;; constant (lvars makes it variable)
      enddefine;

      define grum ...;
         <code for grum INCLUDING a call of baz>
      enddefine;

      other_function(grum)         ;;; other_function will run grum
   enddefine;

Lexical scoping of baz ensures that when other_function runs grum, grum
will call the baz that was defined in foo, ignoring, for example, a
function baz that is local to other_function. In this context it doesn't
matter whether grum is lexically or dynamically scoped, since only the
value, i.e. the function itself, is passed to other_function, not the
name.

Similarly lexical scoping ensures that if foo return grum as a result,
or stores it in a data structure for future use in an unknown calling
environment, there is never any risk that when it is run it will invoke
any other version of baz than the one defined within foo.

Aaron Sloman,
School of Cognitive and Computing Sciences,
Univ of Sussex, Brighton, BN1 9QN, England
    ARPANET : ·························@nss.cs.ucl.ac.uk
    JANET     ······@cvaxa.sussex.ac.uk
    BITNET:   ·························@uk.ac