From: David Steuber "The Interloper
Subject: A Cry in the Wilderness
Date: 
Message-ID: <36323f66.1005676@news.newsguy.com>
I took a personal day on friday so that I could play with my
computer.  Some fun things to do, I thought, would be to get my XEmacs

set up for the colors I like to use, and a few other creature
comforts.  I am using the exiting "XEmacs 20.4 \"Emerald\" [Lucid]
(i386-suse-linux, Mule) of Wed Aug  5 1998 on Fubini" version of
XEmacs.

I am really going to have to get Internet access working for me on
Linux so that I don't have to boot over to NT to annoy you people.  I
should be able to do news and mail, my primary Internet functions, in
XEmacs.  Hell, there are buttons for those features on the tool bar.

I guess I should just get to the point.  I'll start with stuff that is

relevant to this news group.

I seem to have lost my ability to learn new languages.  It took me
quite a while to grok 'do, and I'm not sure that I am there yet.  Here

is a factorial function from page 89 of Paul Graham's "ANSI Common
Lisp".  Actually, I modified it a little.


(defun factorial (n)
  (if (< n 2)
      1
    (do ((j n (- j 1))
	 (f 1 (* j f)))
	((< j 2) f))))

I added the 'if form because I could call the function with a negative

number and watch all my memory go away.  I changed the end clause a
little later to see if I at least identified that part correctly.
Anyway, the 'do is mostly what is in the book.  On page 87, 'do
was described as taking a list with the values variable, initial, and
update.  Then this sucker is thrown at me.  I can have a whole list of

these things.  This is fine if I know how to compose the list.  I
suppose I could also have a list of forms that would cause the 'do to
bail.

Then there is the show-squares function from the same book.

(defun show-squares (start end)
  (do ((i start (+ i 1)))
      ((> i end) 'done)
    (format t "~A ~A~%" i (* i i))))

Initially, I typed it in wrong.  I had ((> i end)) 'done) instead of
the line in the code.  I didn't catch this one for several minutes.  I

was sitting at my terminal, unjustly cursing Graham for putting broken

code in his book.

What I would like, and this is more an XEmacs issue, is for the editor

to highlight the innermost form my text insertion point is in.  I
think this would be very helpful in seeing just where the heck I am.

Back to more relevant points, 'let.  I apparently don't grok 'let.  I
have the following function that works.

(defun time-conses (n)
  (do ((i n (- i 1)))
      ((< i 1) 'done)
    (cons 'a 'b)))

You may guess by looking at it that it doesn't quite do what I want.
You would guess correctly.

My first effort looked something like this:

(defun time-conses (n)
  (time (do ((i n (- i 1)))
            ((< i 1) 'done)
          (cons 'a 'b))))

CMUCL warned me that time was not in a block, or something, and said
it would interpret the function instead of compiling it.  This isn't
what I intended.  I obviously wanted functionality that looks like
this:

(time (time-conses 1000000))

Let is supposed to establish a block, so I tried to use it.  I think I

tried something like this:

(defun time-conses (p)
  (let (n p)
	(time (do ((i n (- i 1)))
      		((< i 1) 'done)
                (cons 'a 'b)))))

My thinking was that 'n would be a local variable in the block with
the value of 'p.  So I was rather surprised to end up in the
debugger.  I felt pretty buggered, so I guess this was the place to
be.

I tried various permutations, none of them correct.

If anyone can describe 'let to me so that I could actually use it, I
would be very happy.

BTW, do function parameters get their own lexical scope?  Or are there

a bunch of variables siting out there, being quietly changed when a
function is called?  In 'C, I am used to automatic variables being
allocated on the stack.  I am really just asking if this is the same
with Lisp.

Well, I will now end this post by padding out your voluminous disk
space with my .xemacs-custom file.  It has my current settings as I
type this.  If anyone has any comments, or helpful additions, I would
love to hear them.  I would have cross-posted this to the XEmacs group

(or is there more than one?), but I don't want to be rude to them.
I've read Kent Pitman's essay on cross-posting, and I agree with him.


My .xemacs-custom file ----------------------------------------------

(custom-set-variables
 '(ps-default-bg (quote (1.0 1.0 1.0)))
 '(ps-default-fg (quote (0.0 0.0 0.0)))
 '(user-mail-address "david @ david-steuber.com" t)
 '(query-user-mail-address nil))
(custom-set-faces)

;; Using customizations trashes setings in custom-set-variables up top
;; So let's try putting stuff here
(custom-set-variables
 '(inhibit-startup-message t t)
 '(display-warning-minimum-level 'error t))

;; Some XEmacs custom entries given to me by Matthias H�lzl
(autoload 'cmulisp   "ilisp" "Inferior CMU Common LISP." t)
(setq cmulisp-program "/usr/bin/lisp -core
/home/david/cmucl/lisp.core")
;; End Matthias H�lzl

;; I like line numbers in the status bar
(line-number-mode 1)

;;;Wipe out all those #files# when ^x^s is done
(setq delete-auto-save-files t)
;;;Don't make backups
(setq backup-inhibited t)

;; Set up font-lock-mode
(setq font-lock-maximum-decoration t)
(setq font-lock-maximum-size 512000)
(font-lock-mode 1)

;;; Set the colors I want

;; Build list of faces to do through
(defvar my-face-list) 
(setq my-face-list (face-list nil))

;; do it
(dolist (x my-face-list)
	(set-face-property x 'background "#1f1f1f")) ; not quite black

(dolist (x my-face-list)
	(set-face-property x 'foreground "#00ff00")) ; green

;; Some faces were defined as red, green, yellow and blue.  I just
blasted them.  The least I can do is
;; fix the foreground portion
(set-face-property 'red 'foreground "#FF0000") ;red
(set-face-property 'blue 'foreground "#0000FF") ;blue
(set-face-property 'yellow 'foreground "#FFFF00") ;yellow

;font-lock-doc-string-face
(set-face-property 'font-lock-doc-string-face 'foreground "#FFFF00")
;yellow
;font-lock-preprocessor-face
(set-face-property 'font-lock-preprocessor-face 'foreground "#0000aF")
;dark blue
;font-lock-keyword-face
(set-face-property 'font-lock-keyword-face 'foreground "#aF00aF")
;dark magenta
;font-lock-variable-name-face
(set-face-property 'font-lock-variable-name-face 'foreground
"#00FFFF") ;cyan
;font-lock-comment-face 
(set-face-property 'font-lock-comment-face 'foreground "#FFFFFF")
;white
;font-lock-reference-face
(set-face-property 'font-lock-reference-face 'foreground "#0000FF")
;blue
;font-lock-string-face
(set-face-property 'font-lock-string-face 'foreground "#aF0000") ;dark
red
;font-lock-function-name-face
(set-face-property 'font-lock-function-name-face 'foreground
"#00aF00") ;dark green
;font-lock-type-face
(set-face-property 'font-lock-type-face 'foreground "#007F7F") ;dark
cyan
;mouse pointer
(set-face-property 'pointer 'foreground "#FFFF00") ;yellow
;text insertion point
(set-face-property 'text-cursor 'foreground "#0000FF") ;blue
(set-face-property 'text-cursor 'background "#FFFF00") ;yellow
;;modeline stuff
(set-face-property 'modeline 'background "#4f4f4f") ;dark grey
(set-face-property 'modeline-buffer-id 'foreground "#FFFF00") ;yellow
(set-face-property 'modeline-buffer-id 'background "#4f4f4f") ;dark
grey
(set-face-property 'modeline-mousable 'foreground "#FF0000") ;red
(set-face-property 'modeline-mousable 'background "#4f4f4f") ;dark
grey
(set-face-property 'modeline-mousable-minor-mode 'foreground
"#FFCF00") ;orange
(set-face-property 'modeline-mousable-minor-mode 'background
"#4f4f4f") ;dark grey
;;I-search
(set-face-property 'isearch 'foreground "#FF0000") ;red
(set-face-property 'isearch 'background "#006f6f") ;dark cyan
;;Region
(set-face-property 'zmacs-region 'background "#3f6f6f") ;de-saturated
dark cyan
;;highlight
(set-face-property 'highlight 'background "#00004f") ;dark blue

;; The following is displayed by a start bar on my machine, but I want
it anyway.
;; For some reason, it must come after setting the face colors, or it
looks weird
(setq display-time-day-and-date t)
(display-time)



--
David Steuber (ver 1.31.2a)
http://www.david-steuber.com
To reply by e-mail, replace trashcan with david.

So I have this chicken, see?  And it hatched from this egg, see?  But
the egg wasn't laid by a chicken.  It was cross-laid by a turkey.

From: Steve Gonedes
Subject: Re: A Cry in the Wilderness
Date: 
Message-ID: <m2hfwtl7xi.fsf@KludgeUnix.com>
········@david-steuber.com (David Steuber "The Interloper") writes:

< I am really going to have to get Internet access working for me on
< Linux so that I don't have to boot over to NT to annoy you people.  I
< should be able to do news and mail, my primary Internet functions, in
< XEmacs.  Hell, there are buttons for those features on the tool bar.

Does your ISP use CHAP or any of that nonsence? If not, it can be
complicated.

If you have CHAP, PAP, or whatever it is - I may be able to give you
some advice since I have to use CPAP (whatever it's called) and found
it more complex that the normal method.

< Then there is the show-squares function from the same book.
<
< (defun show-squares (start end)
<   (do ((i start (+ i 1)))
<       ((> i end) 'done)
<     (format t "~A ~A~%" i (* i i))))
<
< Initially, I typed it in wrong.  I had ((> i end)) 'done) instead of
< the line in the code.  I didn't catch this one for several minutes.  I

I though `do' was very difficult as well when I first came across it.
In fact I remeber this exact problem. I couldn't figure out what the
'DONE, was doing...

< was sitting at my terminal, unjustly cursing Graham for putting broken

I remeber this part as well.

< Back to more relevant points, 'let.  I apparently don't grok 'let.  I
< have the following function that works.
<
< (defun time-conses (n)
<   (do ((i n (- i 1)))
<       ((< i 1) 'done)
<     (cons 'a 'b)))
<
< You may guess by looking at it that it doesn't quite do what I want.
< You would guess correctly.

It returns 'DONE? A better version (imho) is

(defun time-conses (n)
  (dotimes (i n)
    (cons 'a 'b))
 'done).

(time (time-conses 1000)) =>
; cpu time (non-gc) 0 msec user, 0 msec system
; cpu time (gc)     0 msec user, 0 msec system
; cpu time (total)  0 msec user, 0 msec system
; real time  0 msec
; space allocation:
;  1,001 cons cells, 0 symbols, 32 other bytes, 0 static bytes
DONE

There is also the loop, which can be complicated because there are so
many ways to use it.

(defun time-conses (n)
   (loop repeat n
      do (cons 'a 'b))
 'done)

The function DO, seems almost `low-level' to me for some reason. It's
very useful, but hard to read at a glance. The functions dotimes, and
dolist, are essentially interfaces to the DO form. You can verify this
by using macroexpand-1.

(macroexpand-1 '(dotimes (i 3) (print i)))

=> (DO ((I 0 (1+ I)))
       ((>= I 3))
     (DECLARE (TYPE (INTEGER 0 3) I))
     (PRINT I))

The macroexpand-1 will only expand one level of macros, macroexpand
will probably change both forms into a bunch of goto (tagbody and go
in lisp) statements.

< Let is supposed to establish a block, so I tried to use it.  I think I
<
< tried something like this:
<
< (defun time-conses (p)
<   (let (n p)
< 	(time (do ((i n (- i 1)))
<       		((< i 1) 'done)
<                 (cons 'a 'b)))))
<
< My thinking was that 'n would be a local variable in the block with
< the value of 'p.  So I was rather surprised to end up in the
< debugger.  I felt pretty buggered, so I guess this was the place to
< be.

Actually, defun should create a new block. You can always use BLOCK to
introduce a new block (not usually needed though).

Also, you set N and P to nil. Should be, (let ((n p)) ...).

< If anyone can describe 'let to me so that I could actually use it, I
< would be very happy.

(let ((x 12) (y something) z)
  ...)

x = 12, y = the value of something, and z = nil.

< BTW, do function parameters get their own lexical scope? Or are
< there a bunch of variables siting out there, being quietly changed
< when a function is called? In 'C, I am used to automatic variables
< being allocated on the stack. I am really just asking if this is the
< same with Lisp.

I think you can have it both ways. Variables that are returned from
the function are probably not allocated on the stack. Local functions
are probably not allocated on the stack either. You can recommend that
some variable or function be allocated on the stack by declaring it to
have dynamic-extent (rather than indefinite extent). This is probably
only useful for local functions though (since they can be returned and
packaged up someplace else). I think most lisp compilers will do the
right thing with values bound in a let form by default though.

< Well, I will now end this post by padding out your voluminous disk
< space with my .xemacs-custom file.  It has my current settings as I
< type this.  If anyone has any comments, or helpful additions, I would
< love to hear them.  I would have cross-posted this to the XEmacs group
<
< (or is there more than one?), but I don't want to be rude to them.
< I've read Kent Pitman's essay on cross-posting, and I agree with him.
<
<
< My .xemacs-custom file ----------------------------------------------
<
< (custom-set-variables
<  '(ps-default-bg (quote (1.0 1.0 1.0)))
<  '(ps-default-fg (quote (0.0 0.0 0.0)))
<  '(user-mail-address "david @ david-steuber.com" t)
<  '(query-user-mail-address nil))
< (custom-set-faces)

You could probably do something like,

(setq ps-default-bg '(1.0 1.0 1.0)
      ps-default-fg '(0 0 0))

(setq-default user-mail-address "david @ david-steuber.com"
              query-user-mail-address nil)

I wish custom would do that by default. It's not much more work (since
it has to do it at run time anyway). The problem is you can't play
with the custom-settings, which makes emacs seem more intimidating (to
me at least). Like what does the third value `t' do? I personally like
the package browser (C-h p).


< ;; I like line numbers in the status bar
< (line-number-mode 1)

You could probably do, (column-number-mode 1), if you'd like that as well.

[ faces ... ]

Setting colors is a royal pain in the butt. Drives me nuts.

< (setq display-time-day-and-date t)
< (display-time)

You may like,

(setq display-time-day-and-date t
    display-time-24hr-format t).

Have fun...
From: David Steuber "The Interloper
Subject: Re: A Cry in the Wilderness
Date: 
Message-ID: <3632b333.30650763@news.newsguy.com>
On 25 Oct 1998 02:05:52 GMT, Steve Gonedes <········@worldnet.att.net>
claimed or asked:

% < I am really going to have to get Internet access working for me on
% < Linux so that I don't have to boot over to NT to annoy you people.  I
% < should be able to do news and mail, my primary Internet functions, in
% < XEmacs.  Hell, there are buttons for those features on the tool bar.
% 
% Does your ISP use CHAP or any of that nonsence? If not, it can be
% complicated.

The current problem is my ISDN card is not supported by Linux.  I plan
to get an ISDN router and ethernet card when I have a little cash to
spare.  Hopefully, the router will just work.
 
% < (custom-set-variables
% <  '(ps-default-bg (quote (1.0 1.0 1.0)))
% <  '(ps-default-fg (quote (0.0 0.0 0.0)))
% <  '(user-mail-address "david @ david-steuber.com" t)
% <  '(query-user-mail-address nil))
% < (custom-set-faces)
% 
% You could probably do something like,
% 
% (setq ps-default-bg '(1.0 1.0 1.0)
%       ps-default-fg '(0 0 0))

The first form is set by M-x customize (or was it a menu command?).
It gets re-written if you make changes in custom.  I discovered that
the hard way.
 
% (setq-default user-mail-address "david @ david-steuber.com"
%               query-user-mail-address nil)
% 
% I wish custom would do that by default. It's not much more work (since
% it has to do it at run time anyway). The problem is you can't play
% with the custom-settings, which makes emacs seem more intimidating (to
% me at least). Like what does the third value `t' do? I personally like
% the package browser (C-h p).
% 
% 
% < ;; I like line numbers in the status bar
% < (line-number-mode 1)
% 
% You could probably do, (column-number-mode 1), if you'd like that as well.

I think I would.  Didn't know about it.

% Setting colors is a royal pain in the butt. Drives me nuts.

I think it only took me six or twelve hours of continual
experimentation.  I still don't know what all the faces are for, so I
probably defaulted some things to my colors that I shouldn't have.

% < (setq display-time-day-and-date t)
% < (display-time)
% 
% You may like,
% 
% (setq display-time-day-and-date t
%     display-time-24hr-format t).
% 
% Have fun...

So I can get 24 hour!  I was wondering how to set that.  You know, you
can apropos and describe-x until your face is a not so intelligent
shade of the color blue and still not find out how to do these little
things.

For some reason, my XEmacs isn't auto-copying selected regions.  I
don't suppose someone here knows how to do that?  Maybe that question
has been asked in the XEmacs group.  I guess I should hit dejanews.

--
David Steuber (ver 1.31.2a)
http://www.david-steuber.com
To reply by e-mail, replace trashcan with david.

"Ignore reality there's nothing you can do about it..."
-- Natalie Imbruglia "Don't you think?"
From: Barry Margolin
Subject: Re: A Cry in the Wilderness
Date: 
Message-ID: <MEBY1.63$VI.1167623@burlma1-snr1.gtei.net>
In article <··············@KludgeUnix.com>,
Steve Gonedes  <········@worldnet.att.net> wrote:
>The function DO, seems almost `low-level' to me for some reason. It's
>very useful, but hard to read at a glance. The functions dotimes, and
>dolist, are essentially interfaces to the DO form. You can verify this
>by using macroexpand-1.

DO was one of the first iteration macros added to Lisp (MACLISP,
specifically) back in the 70's.  It's intended to be a fairly general,
powerful iteration mechanism -- you can iterate multiple variables, and use
arbitrary initialization and update forms.  As you note, it has since been
augmented by simpler, higher-level iteration mechanisms like DOTIMES and
DOLIST which express some of the most common iterations.

-- 
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
From: Gareth McCaughan
Subject: Re: A Cry in the Wilderness
Date: 
Message-ID: <86vhl7wb2p.fsf@g.pet.cam.ac.uk>
David Steuber wrote:

> I seem to have lost my ability to learn new languages.  It took me
> quite a while to grok 'do, and I'm not sure that I am there yet.

DO is powerful but hard to read. Most uses of DO can be rewritten
as simple applications of DOTIMES, DOLIST or LOOP. (LOOP can also
be pretty incomprehensible, but only when you do complicated things
with it. For most simple iterations, it's very clear.)

> Here is a factorial function from page 89 of Paul Graham's "ANSI Common
> Lisp".  Actually, I modified it a little.
> 
> (defun factorial (n)
>   (if (< n 2)
>       1
>     (do ((j n (- j 1))
> 	 (f 1 (* j f)))
> 	((< j 2) f))))
> 
> I added the 'if form because I could call the function with a negative
> number and watch all my memory go away.

Um? The termination test in the DO should deal with that already.

Here's what DO does, in terms that should be familiar to one
more used to more mainstream languages.

    (do ((var initially after-each-step)
         (var initially after-each-step)
         ...)
        (condition result)
      form form ...)

means, roughly,

    Establish a block (in the "C" sense of the term)
    in which each "var" is set to "initially".

    Check whether "condition" comes out true.
    If it does, the value of the DO form is "result"
    and we're done.

    Evaluate each of the "form"s. (There needn't be any,
    incidentally: in which case, this step does nothing.)

    Set each variable to its corresponding "after-each-step".

    Go back to the instruction "Check whether ..." and repeat.

Some details this doesn't cover:

    When I say that "var" is set to "initially" or "after-each-step"
    I mean it's set to the result of evaluating those forms. So
    you can have (foo 1 (+ foo 1)) meaning that foo starts off at 1
    and increases by 1 each time around the loop.

    Similarly, "condition" and "result" get evaluated.

    You can omit the "after-each-step"s.

    The "initially"s are all evaluated *before any of the "var"s
    get set*. More precisely, before any of them get bound.
    Similarly, the "after-each-step"s are all evaluated with the
    old values of the variables. That may sound complicated, so
    here's an example. If I do

        (let ((x 10))
          (do ((x 0 y)
               (y x x))
              ((zerop y) (list x y))
            (format t "Boo! ~A ~A~%" x y)
        ))

    then the sequence of actions will be:

        Set x to 0 and y to 10 (*not* to 0, because when that "x"
        get evaluated, the binding of x that's in force is the
        one created by the "let").

        Check whether y is 0. It isn't, so we aren't done yet.

        Output "Boo!" followed by the values of x and y, followed
        by a newline. (So we get "Boo! 0 10".)

        Set x to the current value of y, and y to the current
        value of x. So now x is 10 and y is 0. (y is *not* 10,
        because that "x" gets the old value of y.)

        Check whether y is 0. It is, so we're done.

        The result of the DO is therefore the value of (list x y),
        i.e. the value of (list 10 0), i.e. the list (10 0).

    So, this prints "Boo! 0 10" and then returns (10 0). (Your
    Lisp system will probably then print (10 0) before the
    next prompt.)

Now, let's look at the particular DO form you have, without the
enclosing IF.

    (do ((j n (- j 1))    ;; j begins at n, and decreases by 1 each time.
         (f 1 (* f j)))   ;; f begins at 1, and is multiplied by j each time.
        ((< j 2) f)       ;; when j gets below 2, return f.
    )

If we evaluate this with n=3, the sequence of operations is

    j=3, f=1       ; initialise
    is j<2? no     ; test for end
    j=j-1, f=f*3   ; update -- NB f is multipled by the OLD value of j
    [so j=2, f=3]
    is j<2? no     ; test for end
    j=j-1, f=f*2   ; update
    [so j=1, f=6]
    is j<2? YES    ; test for end
    result is f    ; so return
    [so result is 6]

> these things.  This is fine if I know how to compose the list.  I
> suppose I could also have a list of forms that would cause the 'do to
> bail.

No, 'fraid not. Just one.

> (defun time-conses (n)
>   (time (do ((i n (- i 1)))
>             ((< i 1) 'done)
>           (cons 'a 'b))))
> 
> CMUCL warned me that time was not in a block, or something, and said
> it would interpret the function instead of compiling it.

Two things.

Firstly, if you make that definition and do (compile 'time-conses)
then all will be well.

Secondly, its complaint is actually the opposite of what you think.
It's complaining that the TIME form *is* inside a "non-null
environment". The reason why this is a problem is rather subtle,
so you should either skip everything until the next bit of quoted
text or else take a deep breath...

First, some definitions.

A "binding" of a variable is something that associates a variable
with a value. (Or, for some authors, something that associates a
variable with a particular location where its value can be stored.)

An "environment" is a collection of bindings.

A "closure" is a function together with an environment in which
its code will be run.

That last one is a bit weird, especially if you're not used to
Lisp-like languages. It means that you can do things like this:
(Warning: this is a lengthy digression.)

    (defun adder (n)
      (lambda (x) (+ x n)))

That LAMBDA form evaluates to a function of one variable, X, that
adds N to the function. Here N is bound in the environment established
by the ADDER function; which is just a pretentious way of saying that
N refers to the local variable N created when ADDER was called.

But note that this function can survive after ADDER has finished!
I can do

    (setq add-3 (adder 3))
    (funcall add-3 10)      ;; *not* (add-3 10), for irrelevant reasons

and that second form will evaluate to 13.

So, this thing I've stored in the variable ADD-3 isn't just a
function. It's a function *plus environment*.

You may be thinking "surely it's really just a function, because
that reference to n can disappear and just be replaced by 3".
That's not true, because the function can also allow n to be
changed. Consider the following abomination:

    (defun adder-and-changer (n)
      (list
        (lambda (x) (+ x n))
        (lambda (x) (setq n x))))

The result of (adder-and-changer 3) is a list of two functions.
The first is a function that -- at the moment -- returns its
argument plus 3. The second is a function that changes what
the first function adds!

    (setq thing (adder-and-changer 3))
    (setq add-3 (first thing))      ;; terrible name, really
    (setq change-3 (second thing))  ;; even more terrible name
    (funcall add-3 10)     ;; returns 13
    (funcall change-3 99)
    (funcall add-3 10)     ;; returns 109

So, ADD-3 and CHANGE-3 here are closures with the same environment
and different functions. If I evaluated (adder 3) twice, I'd get
closures with the same function and different environments.

OK, end of lengthy digression. Why is all this relevant? Well,
when CMU CL sees (time <blah>) it tries to compile <blah>. And,
because of the way its compiler works, what this actually means
is that it compiles a function of no arguments -- in effect,
  (lambda () <blah>)
-- and then times calling that.

Now, suppose all this takes place in a non-null environment and
in interpreted code. In other words, suppose there are some
variable bindings surrounding the (time ...) form. Then we hit
a problem, which is that environments are represented in very
different ways in compiled code and in interpreted code.

In typical systems -- I don't know what CMU CL does, because
I haven't looked at its internals -- an environment in interpreted
code is implemented as some sort of lookup table mapping symbols
to values. So it might be something like an association list
((n . 3)), or a hash table, or something like that. In compiled
code, we don't want to have to search some kind of table every
time we refer to a variable. Instead, *at compile time* we have
a table mapping symbols to locations -- typically, offsets into
the stack or something like that -- and once the code is compiled
it expects to find the relevant stuff at the right place in the
stack when it's called.

Now, this is a serious mismatch. It would be really awkward if
our compiled code had to read and write the variable bindings
stored in an association list or a hash table; what's more,
it would need to be different code from what we'd use if there
wasn't an interpreted environment surrounding it.

Therefore, CMU CL just refuses to compile code that's surrounded
by an interpreted environment. Hence the warning you got.

> Let is supposed to establish a block, so I tried to use it.

One word of caution: "block" has a special meaning in Lisp,
which differs from its meaning in languages like C. I think
it's the C-like meaning you have in mind here.

> I think I tried something like this:
> 
> (defun time-conses (p)
>   (let (n p)

ooops! you mean

    (let ((n p))

Someone else has already posted an article explaining what LET does,
so I won't go into details.

> 	(time (do ((i n (- i 1)))
>       		((< i 1) 'done)
>                 (cons 'a 'b)))))
> 
> My thinking was that 'n would be a local variable in the block with
> the value of 'p.  So I was rather surprised to end up in the
> debugger.  I felt pretty buggered, so I guess this was the place to
> be.

It will have bound n to nil, and then complained when you tried to
compare it with 1.

> BTW, do function parameters get their own lexical scope?

Yes, they do.

>                                                           Or are there
> a bunch of variables siting out there, being quietly changed when a
> function is called?  In 'C, I am used to automatic variables being
> allocated on the stack.  I am really just asking if this is the same
> with Lisp.

It's not the same, because those variable bindings can get
captured in closures -- see the examples in my long digression
above. However, when that doesn't happen the semantics are
very much as in C.

One thing worth mentioning is that LET is like DO in that
if you LET several variables at once the right-hand sides
are all evaluated before any of the variables are bound.
This is different from C, where

    { int x=1, y=x+1, z=y+1;
      printf("%d %d %d\n", x, y, z);
    }

will print "1 2 3". A naive translation into LISP would be

    (let ((x 1) (y (+ x 1)) (z (+ y 1)))
      (format t "~D ~D ~D~%" x y z))

which would complain about X being unbound when evaluating (+ x 1)
and about Y being unbound when evaluating (+ y 1).

If you want C-like behaviour -- and one quite often does -- you
can use LET* (and, instead of DO, DO*) which differs precisely
in that those bindings happen sequentially:

    (let* ((x 1) (y (+ x 1)) (z (+ y 1)))
      (format t "~D ~D ~D~%" x y z))

will print "1 2 3".

-- 
Gareth McCaughan       Dept. of Pure Mathematics & Mathematical Statistics,
·····@dpmms.cam.ac.uk  Cambridge University, England.
From: rusty craine
Subject: Re: A Cry in the Wilderness
Date: 
Message-ID: <71292n$crn$1@excalibur.flash.net>
Gareth McCaughan wrote in message <··············@g.pet.cam.ac.uk>...

OMG a insightful post on lisp and on comp.lang.lisp.  Thanks Gareth I
enjoyed your well written explaination.

Rusty Craine

>David Steuber wrote:
>
>> I seem to have lost my ability to learn new languages.  It took me
>> quite a while to grok 'do, and I'm not sure that I am there yet.
>
>DO is powerful but hard to read. Most uses of DO can be rewritten
>as simple applications of DOTIMES, DOLIST or LOOP. (LOOP can also
>be pretty incomprehensible, but only when you do complicated things
>with it. For most simple iterations, it's very clear.)
>
>> Here is a factorial function from page 89 of Paul Graham's "ANSI Common
>> Lisp".  Actually, I modified it a little.
>>
>> (defun factorial (n)
>>   (if (< n 2)
>>       1
>>     (do ((j n (- j 1))
>> (f 1 (* j f)))
>> ((< j 2) f))))
>>
>> I added the 'if form because I could call the function with a negative
>> number and watch all my memory go away.
>
>Um? The termination test in the DO should deal with that already.
>
>Here's what DO does, in terms that should be familiar to one
>more used to more mainstream languages.
>
>    (do ((var initially after-each-step)
>         (var initially after-each-step)
>         ...)
>        (condition result)
>      form form ...)
>
>means, roughly,
>
>    Establish a block (in the "C" sense of the term)
>    in which each "var" is set to "initially".
>
>    Check whether "condition" comes out true.
>    If it does, the value of the DO form is "result"
>    and we're done.
>
>    Evaluate each of the "form"s. (There needn't be any,
>    incidentally: in which case, this step does nothing.)
>
>    Set each variable to its corresponding "after-each-step".
>
>    Go back to the instruction "Check whether ..." and repeat.
>
>Some details this doesn't cover:
>
>    When I say that "var" is set to "initially" or "after-each-step"
>    I mean it's set to the result of evaluating those forms. So
>    you can have (foo 1 (+ foo 1)) meaning that foo starts off at 1
>    and increases by 1 each time around the loop.
>
>    Similarly, "condition" and "result" get evaluated.
>
>    You can omit the "after-each-step"s.
>
>    The "initially"s are all evaluated *before any of the "var"s
>    get set*. More precisely, before any of them get bound.
>    Similarly, the "after-each-step"s are all evaluated with the
>    old values of the variables. That may sound complicated, so
>    here's an example. If I do
>
>        (let ((x 10))
>          (do ((x 0 y)
>               (y x x))
>              ((zerop y) (list x y))
>            (format t "Boo! ~A ~A~%" x y)
>        ))
>
>    then the sequence of actions will be:
>
>        Set x to 0 and y to 10 (*not* to 0, because when that "x"
>        get evaluated, the binding of x that's in force is the
>        one created by the "let").
>
>        Check whether y is 0. It isn't, so we aren't done yet.
>
>        Output "Boo!" followed by the values of x and y, followed
>        by a newline. (So we get "Boo! 0 10".)
>
>        Set x to the current value of y, and y to the current
>        value of x. So now x is 10 and y is 0. (y is *not* 10,
>        because that "x" gets the old value of y.)
>
>        Check whether y is 0. It is, so we're done.
>
>        The result of the DO is therefore the value of (list x y),
>        i.e. the value of (list 10 0), i.e. the list (10 0).
>
>    So, this prints "Boo! 0 10" and then returns (10 0). (Your
>    Lisp system will probably then print (10 0) before the
>    next prompt.)
>
>Now, let's look at the particular DO form you have, without the
>enclosing IF.
>
>    (do ((j n (- j 1))    ;; j begins at n, and decreases by 1 each time.
>         (f 1 (* f j)))   ;; f begins at 1, and is multiplied by j each
time.
>        ((< j 2) f)       ;; when j gets below 2, return f.
>    )
>
>If we evaluate this with n=3, the sequence of operations is
>
>    j=3, f=1       ; initialise
>    is j<2? no     ; test for end
>    j=j-1, f=f*3   ; update -- NB f is multipled by the OLD value of j
>    [so j=2, f=3]
>    is j<2? no     ; test for end
>    j=j-1, f=f*2   ; update
>    [so j=1, f=6]
>    is j<2? YES    ; test for end
>    result is f    ; so return
>    [so result is 6]
>
>> these things.  This is fine if I know how to compose the list.  I
>> suppose I could also have a list of forms that would cause the 'do to
>> bail.
>
>No, 'fraid not. Just one.
>
>> (defun time-conses (n)
>>   (time (do ((i n (- i 1)))
>>             ((< i 1) 'done)
>>           (cons 'a 'b))))
>>
>> CMUCL warned me that time was not in a block, or something, and said
>> it would interpret the function instead of compiling it.
>
>Two things.
>
>Firstly, if you make that definition and do (compile 'time-conses)
>then all will be well.
>
>Secondly, its complaint is actually the opposite of what you think.
>It's complaining that the TIME form *is* inside a "non-null
>environment". The reason why this is a problem is rather subtle,
>so you should either skip everything until the next bit of quoted
>text or else take a deep breath...
>
>First, some definitions.
>
>A "binding" of a variable is something that associates a variable
>with a value. (Or, for some authors, something that associates a
>variable with a particular location where its value can be stored.)
>
>An "environment" is a collection of bindings.
>
>A "closure" is a function together with an environment in which
>its code will be run.
>
>That last one is a bit weird, especially if you're not used to
>Lisp-like languages. It means that you can do things like this:
>(Warning: this is a lengthy digression.)
>
>    (defun adder (n)
>      (lambda (x) (+ x n)))
>
>That LAMBDA form evaluates to a function of one variable, X, that
>adds N to the function. Here N is bound in the environment established
>by the ADDER function; which is just a pretentious way of saying that
>N refers to the local variable N created when ADDER was called.
>
>But note that this function can survive after ADDER has finished!
>I can do
>
>    (setq add-3 (adder 3))
>    (funcall add-3 10)      ;; *not* (add-3 10), for irrelevant reasons
>
>and that second form will evaluate to 13.
>
>So, this thing I've stored in the variable ADD-3 isn't just a
>function. It's a function *plus environment*.
>
>You may be thinking "surely it's really just a function, because
>that reference to n can disappear and just be replaced by 3".
>That's not true, because the function can also allow n to be
>changed. Consider the following abomination:
>
>    (defun adder-and-changer (n)
>      (list
>        (lambda (x) (+ x n))
>        (lambda (x) (setq n x))))
>
>The result of (adder-and-changer 3) is a list of two functions.
>The first is a function that -- at the moment -- returns its
>argument plus 3. The second is a function that changes what
>the first function adds!
>
>    (setq thing (adder-and-changer 3))
>    (setq add-3 (first thing))      ;; terrible name, really
>    (setq change-3 (second thing))  ;; even more terrible name
>    (funcall add-3 10)     ;; returns 13
>    (funcall change-3 99)
>    (funcall add-3 10)     ;; returns 109
>
>So, ADD-3 and CHANGE-3 here are closures with the same environment
>and different functions. If I evaluated (adder 3) twice, I'd get
>closures with the same function and different environments.
>
>OK, end of lengthy digression. Why is all this relevant? Well,
>when CMU CL sees (time <blah>) it tries to compile <blah>. And,
>because of the way its compiler works, what this actually means
>is that it compiles a function of no arguments -- in effect,
>  (lambda () <blah>)
>-- and then times calling that.
>
>Now, suppose all this takes place in a non-null environment and
>in interpreted code. In other words, suppose there are some
>variable bindings surrounding the (time ...) form. Then we hit
>a problem, which is that environments are represented in very
>different ways in compiled code and in interpreted code.
>
>In typical systems -- I don't know what CMU CL does, because
>I haven't looked at its internals -- an environment in interpreted
>code is implemented as some sort of lookup table mapping symbols
>to values. So it might be something like an association list
>((n . 3)), or a hash table, or something like that. In compiled
>code, we don't want to have to search some kind of table every
>time we refer to a variable. Instead, *at compile time* we have
>a table mapping symbols to locations -- typically, offsets into
>the stack or something like that -- and once the code is compiled
>it expects to find the relevant stuff at the right place in the
>stack when it's called.
>
>Now, this is a serious mismatch. It would be really awkward if
>our compiled code had to read and write the variable bindings
>stored in an association list or a hash table; what's more,
>it would need to be different code from what we'd use if there
>wasn't an interpreted environment surrounding it.
>
>Therefore, CMU CL just refuses to compile code that's surrounded
>by an interpreted environment. Hence the warning you got.
>
>> Let is supposed to establish a block, so I tried to use it.
>
>One word of caution: "block" has a special meaning in Lisp,
>which differs from its meaning in languages like C. I think
>it's the C-like meaning you have in mind here.
>
>> I think I tried something like this:
>>
>> (defun time-conses (p)
>>   (let (n p)
>
>ooops! you mean
>
>    (let ((n p))
>
>Someone else has already posted an article explaining what LET does,
>so I won't go into details.
>
>> (time (do ((i n (- i 1)))
>>       ((< i 1) 'done)
>>                 (cons 'a 'b)))))
>>
>> My thinking was that 'n would be a local variable in the block with
>> the value of 'p.  So I was rather surprised to end up in the
>> debugger.  I felt pretty buggered, so I guess this was the place to
>> be.
>
>It will have bound n to nil, and then complained when you tried to
>compare it with 1.
>
>> BTW, do function parameters get their own lexical scope?
>
>Yes, they do.
>
>>                                                           Or are there
>> a bunch of variables siting out there, being quietly changed when a
>> function is called?  In 'C, I am used to automatic variables being
>> allocated on the stack.  I am really just asking if this is the same
>> with Lisp.
>
>It's not the same, because those variable bindings can get
>captured in closures -- see the examples in my long digression
>above. However, when that doesn't happen the semantics are
>very much as in C.
>
>One thing worth mentioning is that LET is like DO in that
>if you LET several variables at once the right-hand sides
>are all evaluated before any of the variables are bound.
>This is different from C, where
>
>    { int x=1, y=x+1, z=y+1;
>      printf("%d %d %d\n", x, y, z);
>    }
>
>will print "1 2 3". A naive translation into LISP would be
>
>    (let ((x 1) (y (+ x 1)) (z (+ y 1)))
>      (format t "~D ~D ~D~%" x y z))
>
>which would complain about X being unbound when evaluating (+ x 1)
>and about Y being unbound when evaluating (+ y 1).
>
>If you want C-like behaviour -- and one quite often does -- you
>can use LET* (and, instead of DO, DO*) which differs precisely
>in that those bindings happen sequentially:
>
>    (let* ((x 1) (y (+ x 1)) (z (+ y 1)))
>      (format t "~D ~D ~D~%" x y z))
>
>will print "1 2 3".
>
>--
>Gareth McCaughan       Dept. of Pure Mathematics & Mathematical Statistics,
>·····@dpmms.cam.ac.uk  Cambridge University, England.
From: David Steuber "The Interloper
Subject: Re: A Cry in the Wilderness
Date: 
Message-ID: <363a4740.13459663@news.newsguy.com>
On Mon, 26 Oct 1998 10:49:06 -0600, "rusty craine"
<········@flash.net> claimed or asked:

% OMG a insightful post on lisp and on comp.lang.lisp.  Thanks Gareth I
% enjoyed your well written explaination.

Yes, I liked it too.  Unfortunately, sleep depravation means I will
have to read it again.  Maybe several times.  I shall sleep first!

--
David Steuber (ver 1.31.2a)
http://www.david-steuber.com
To reply by e-mail, replace trashcan with david.

"Ignore reality there's nothing you can do about it..."
-- Natalie Imbruglia "Don't you think?"