From: Aaron Sloman
Subject: Re: What's the value of lexical scoping?
Date: 
Message-ID: <486@cvaxa.sussex.ac.uk>
From: ·····@comp.lancs.ac.uk (Simon Brooke)

>Part of the power and expressiveness of LISP is that we can,
>when we want to, and when we know what we're doing, write functions which
>are sensitive to changes in their environment. If you don't like this, you
>will find that there are plenty of other *very good* languages (Pascal,
>Modula, Ada - even Scheme) which cater for your needs. Don't come and mess
>up the one language which has the expressiveness to do this.

The "one" language? No. Pop-11 is another language that allows dynamic
scoping. (For those who don't know it, there's an enthusiastic review of
Alphapop, a subset of Pop-11 for the Mac, in Byte May 1988).

The full version of Pop-11, currently available only in the Poplog
system, allows both lexical and dynamic scoping. For historical reasons
dynamic scoping is the default (ie input and output local parameters
default to being dynamically scoped if not explicitly declared lexical
(using "lvars", "lconstant" or "dlvars").

Pop-11 is a sort of mixture of Lisp (dynamic scoping is available, along
with macros, lists garbage collection, etc), Scheme (functions are
ordinary values of variables, and in all respects first class objects,
and lexical scoping is available), Pascal (rich, readable syntax,
records, arrays), Forth (use of explicit stack for passing arguments and
results). It also includes partial application, a pattern matcher, a
lightweight process mechanism and tools for creating new incremental
compilers, which is how the Poplog system can include compilers for a
variety of languages (Pop-11, Prolog, Common Lisp, ML, and other
user-implemented languages).

Pop-11 is a much expanded derivative of Pop-2 the language that was used
for many years in the Edinburgh Universith AI department.

One interesting fact about Pop-11 is that when lexical scoping became
available (version 10.2 1985) many users (including the Poplog system
developers) found themselves switching from dynamic scoping as their
default to lexical,
    (a) because they produced were fewer bugs due to unintended
    interactions between procedures taking procedures as arguments,
    (b) because it improved efficiency. Moreover, they also became aware
    of additional expressive power available.

E.g. here's a procedure that takes two procedures and returns a third
procedure which is their functional composition:

    define compose(f1, f2);
        lvars procedure (f1, f2);

        define lvars f3(x);
            f2(f1(x))
        enddefine;

        return(f3)
    enddefine;

So, using it:

    vars root4;

    compose(sqrt,sqrt) -> root4;
    root4(16) =>
    ** 2.0

A procedure that takes a start number and an increment number and
returns two procedures, a number generator and a "reset" procedure:

    define make_generator(start, incr) -> generator -> reset;
        lvars start, incr, generator, reset, count=start;

        ;;; create the number generator procedure
        procedure();
            count;                  ;;; result left on stack
            count + incr -> count;  ;;; increment for next time
        endprocedure -> generator;  ;;; procedure assigned to generator

        procedure();
            start -> count;
        endprocedure -> reset;      ;;; procedure assigned to reset
    enddefine;

    vars gen1, reset1, gen2, reset2; ;;; declare some global variables

    ;;; Create two generators and their "reset" procedures, one to
    ;;; generate multiples of 3, the second multiples of 5.

    make_generator(3,3) -> gen1 -> reset1;
    make_generator(5,5) -> gen2 -> reset2;

    gen1() =>       ;;; run gen1 and print out its result
    ** 3
    gen1() =>
    ** 6
    gen2() =>
    ** 5
    gen2() =>
    ** 10
    ;;; reset the first sequence
    reset1();
    gen1() =>
    ** 3
    gen2() =>
    ** 15

So, using lexical scoping it is very easy to define a procedure that
(each time it is invoked) creates a family of procedures that share a
private environment.

(For some of the simpler cases you can also do this using partial
application, which is a bit more efficient, though less elegant).

I suspect Lisp (and therefore perhaps AI) would have a much healthier
future as a general purpose language if it used the richer, more
readable (for ordinary mortals), syntax of Pop.

Cheers
Aaron Sloman,
School of Cognitive Sciences, Univ of Sussex, Brighton, BN1 9QN, England
    ARPANET : ·························@nss.cs.ucl.ac.uk
              ··········································@relay.cs.net
    JANET     ······@cvaxa.sussex.ac.uk
    BITNET:   ·························@uk.ac
        or    ·······································@cunyvm.cuny.edu

As a last resort (it costs us more...)
    UUCP:     ...mcvax!ukc!cvaxa!aarons
            or ······@cvaxa.uucp