From: J.C. Roberts
Subject: CL: How are "implied lists" handled?
Date: 
Message-ID: <4bttm1heiqsoqtnqov2a5qrmkme4vj0m6d@4ax.com>
#|

I'm having trouble understanding something in the CL HyperSpec.

I call them "implied lists" but I doubt that is the correct name.
For example: http://www.lisp.org/HyperSpec/Body/mac_docm_dost.html#do

(do 
  ({var | (var [init-form [step-form]])}*)    ;implies a list
  (end-test-form result-form*)                ;implies a list
  declaration* 
  {tag | statement}*)
=> result*

To make things bit easier, let's isolate one of the possible forms of 
the above and layout the syntax with comments:

(do
  (var)                         ; IMPLIED list of variables
  (end-test-form result-form*)  ; IMPLIED list of evaluated forms
  declaration*                  ; zero or more unevaluated declarations
  statement*)                   ; zero or more evaluated statements


Or it could be written with the lists actually declared:

(do
  (list var1 ... varN)          ; DECLARED list of variables
  (list                         ; DECLARED list of evaluated forms
    end-test-form               ; a single end-test form
    result-form1                ; the first result-form
    ...               
    result-formN)               ; the returned result-form
  declaration*                  ; zero or more unevaluated declarations
  statement*)                   ; zero or more evaluated statements

|#

;---------------------------------------------------------------------
; So let's look at the first syntax layout above in usable code
;
(format t "~%~%~A" "(DO *) syntax 1")
(setq varsum 0)
(do 
  (var1 var2)                         ; a list of variables
                                      
  ((= 10 varsum)                      ; the evaluated end-test form
   (incf varsum)                      ; an evaluated result-form
   (print varsum)                     ; an evaluated result-form
   varsum)                            ; the returned result-form

  (if (null var1)                     ; evaluated if statement
      (setq var1 0)                   ; then set var1 to 0
      (incf var1))                    ; else increment var1
  (if (null var2)                     ; evaluated statement
      (setq var2 0)                   ; then set var2 to 0
      (incf var2))                    ; else increment var2
  (format t "~%~A~A" "  VAR1=" var1)  ; evaluated statement
  (format t "  ~A~A" "  VAR2=" var2)  ; evaluated statement
  (setq varsum (+ var1 var2)))        ; evaluated statement

;>> (DO *) syntax 1
;>>   VAR1=0    VAR2=0
;>>   VAR1=1    VAR2=1
;>>   VAR1=2    VAR2=2
;>>   VAR1=3    VAR2=3
;>>   VAR1=4    VAR2=4
;>>   VAR1=5    VAR2=5
;>> 11

;---------------------------------------------------------------------
; Though it's basically equivalent to the above I guess the more
; common syntax would probably use (var [init-form [step-form]])
; since it's a lot more simple than managing counters/variables
; in the body statements
;
(format t "~%~%~A" "(DO *) syntax 2")
(setq varsum 0)
(do 
  ((var1 0 (1+ var1))                 ; a list of variable lists
   (var2 0 (1+ var2)))                ; (var [init-form [step-form]])
                                      
  ((= 10 varsum)                      ; the evaluated end-test form
   (incf varsum)                      ; an evaluated result-form
   (print varsum)                     ; an evaluated result-form
   varsum)                            ; the returned result-form

  (format t "~%~A~A" "  VAR1=" var1)  ; evaluated statement
  (format t "  ~A~A" "  VAR2=" var2)  ; evaluated statement
  (setq varsum (+ var1 var2)))        ; evaluated statement

;>> (DO *) syntax 2
;>>   VAR1=0    VAR2=0
;>>   VAR1=1    VAR2=1
;>>   VAR1=2    VAR2=2
;>>   VAR1=3    VAR2=3
;>>   VAR1=4    VAR2=4
;>>   VAR1=5    VAR2=5
;>> 11


;---------------------------------------------------------------------
; Now getting back to the problem of implied lists. In other LISP
; variants, there's nothing wrong with using "long-hand" syntax and
; just explicitly stating functions of the short hand syntax. This
; seems to work to some degree with Common LISP but not always. For
; example this works:

(format t "~%~%~A" "(DO *) syntax 3")
(setq varsum 0)
(do 
  (list (var1 0 (1+ var1))            ; explicitly declare the list of 
   (var2 0 (1+ var2)))                ; (var [init-form [step-form]])
                                      
  ((= 10 varsum)                      ; the evaluated end-test form
   (incf varsum)                      ; an evaluated result-form
   (print varsum)                     ; an evaluated result-form
   varsum)                            ; the returned result-form

  (format t "~%~A~A" "  VAR1=" var1)  ; evaluated statement
  (format t "  ~A~A" "  VAR2=" var2)  ; evaluated statement
  (setq varsum (+ var1 var2)))        ; evaluated statement

;>> (DO *) syntax 3
;>>   VAR1=0    VAR2=0
;>>   VAR1=1    VAR2=1
;>>   VAR1=2    VAR2=2
;>>   VAR1=3    VAR2=3
;>>   VAR1=4    VAR2=4
;>>   VAR1=5    VAR2=5
;>> 11


;---------------------------------------------------------------------
; But the following results in an endless loop in CLISP and LISPWORKS
; and I'm yet to figure out why.
;
(format t "~%~%~A" "(DO *) syntax 4")
(setq varsum 0)
(do 
  (list (var1 0 (1+ var1))            ; explicitly declare the list of 
   (var2 0 (1+ var2)))                ; (var [init-form [step-form]])
                                      
  (list                               ; explicitly declare the list
    (= 10 varsum)                     ; the evaluated end-test form
    (incf varsum)                     ; an evaluated result-form
    (print varsum)                    ; an evaluated result-form
    varsum)                           ; the returned result-form

  (format t "~%~A~A" "  VAR1=" var1)  ; evaluated statement
  (format t "  ~A~A" "  VAR2=" var2)  ; evaluated statement
  (setq varsum (+ var1 var2)))        ; evaluated statement

#|

The second implied list (end-test-form result-form*) seems to be fed
into the (COND *) function with a (return) from the (do *) block 
tacked on the end somehow.

So we've got something like (list a b c d) being passed to (COND *)

  (COND 
    (                                   ; the implied list
      (= 10 varsum)                     ; "a" the evaluated test 
      (incf varsum)                     ; "b" an evaluated statement
      (print varsum)                    ; "c" an evaluated statement
      varsum))                          ; "d" the returned result

The input of (COND *) is actually a list of (implied) lists in the form:

  (cond (list a b c d) (list 1 2 3 4))

hmmmm.... still doesn't make sense?

Does anyone know why an implied list can not be explicitly declared in
only some of the places where they are used?

|#

From: Cameron MacKinnon
Subject: Re: CL: How are "implied lists" handled?
Date: 
Message-ID: <aeednaF5FecJnfLenZ2dnUVZ_tqdnZ2d@rogers.com>
J.C. Roberts wrote:
> ;---------------------------------------------------------------------
> ; Now getting back to the problem of implied lists. In other LISP
> ; variants, there's nothing wrong with using "long-hand" syntax and
> ; just explicitly stating functions of the short hand syntax. This
> ; seems to work to some degree with Common LISP but not always. For
> ; example this works:
> 
> (format t "~%~%~A" "(DO *) syntax 3")
> (setq varsum 0)
> (do 
>   (list (var1 0 (1+ var1))            ; explicitly declare the list of 
>    (var2 0 (1+ var2)))                ; (var [init-form [step-form]])

These other Lisps, do they have macros?

DO is a macro. As such, the (list ...) form above is not evaluated 
before DO sees it, but is passed whole and unevaluated as a list. DO is 
free to do whatever it wants with this information, and is expected to 
return another list of Lisp code which will in turn be fed to the 
compiler. The LIST function never gets called, rather the LIST symbol is 
the first symbol in the list passed to DO. It may help you to understand 
what's going on if you get Lisp to show you explicitly. Try:

(print (macroexpand-1 '(do ...)))

...and you'll see what lower level constructs Lisp expands your DO into. 
In this case, sadly, DO thinks LIST is just another variable (with no 
init-form or step-form). Probably not what you intended.
From: Kaz Kylheku
Subject: Re: CL: How are "implied lists" handled?
Date: 
Message-ID: <1131380849.799447.97370@g44g2000cwa.googlegroups.com>
J.C. Roberts wrote:
> #|
>
> I'm having trouble understanding something in the CL HyperSpec.
>
> I call them "implied lists" but I doubt that is the correct name.
> For example: http://www.lisp.org/HyperSpec/Body/mac_docm_dost.html#do
>
> (do
>   ({var | (var [init-form [step-form]])}*)    ;implies a list
>   (end-test-form result-form*)                ;implies a list

Not sure that ``implies'' is the right word, since an implication is
something you have to infer. Here, the requirement for two lists is
spelled out for you. Even if the {var ... }* generates nothing, the
first list must be there. The second list must contain at least one
form, the end-test-form.

>   declaration*
>   {tag | statement}*)
> => result*
>
> To make things bit easier, let's isolate one of the possible forms of
> the above and layout the syntax with comments:
>
> (do
>   (var)                         ; IMPLIED list of variables
>   (end-test-form result-form*)  ; IMPLIED list of evaluated forms
>   declaration*                  ; zero or more unevaluated declarations
>   statement*)                   ; zero or more evaluated statements
>
>
> Or it could be written with the lists actually declared:
>
> (do
>   (list var1 ... varN)          ; DECLARED list of variables
>   (list                         ; DECLARED list of evaluated forms

Doh, what? Here you are using the symbol LIST as a variable and as the
end-test-form.

The DO operator does not evaluate these lists as expressions. If it
did, then

 (do (x y z) ...)

would not work, because it would complain that there is no function
called X, or that Y and Z are unbound variables.

> ;---------------------------------------------------------------------
> ; Now getting back to the problem of implied lists. In other LISP
> ; variants, there's nothing wrong with using "long-hand" syntax and

What variants? I can't imagine any variant in which it would make sense
to have that kind of ambiguity, to have the implementation guess that
(list bach brahms) is intended to be a function call, but (liszt bach
brahms) is syntax specifying three variables.

> ; just explicitly stating functions of the short hand syntax. This
> ; seems to work to some degree with Common LISP but not always. For
> ; example this works:
>
> (format t "~%~%~A" "(DO *) syntax 3")
> (setq varsum 0)
> (do
>   (list (var1 0 (1+ var1))            ; explicitly declare the list of
>    (var2 0 (1+ var2)))                ; (var [init-form [step-form]])

This only ``works'' because (list (var 1 0 (1+ var1) (var2  0 (1+
var2))) is a list of three var and var-init var-step forms. Those three
forms are:

1. The variable LIST
2. The var-init and var-step form (VAR1 0 (1+ VAR1))
3. The var-init and var-step form (VAR2 0 (1+ VAR1))

The variable LIST is initialized to NIL and ignored in your loop, so it
does nothing.

If the (LIST ...) syntax /did/ work as you think it does, there would
have to be quoting. You see, you cannot write:

  (list (var1 0 ...) (var 2 0 ...))

because LIST is a function and its arguments are evaluated. So the
(VAR1 ...)  and (VAR2 ...) are function calls. You would have to write:

  (list (quote (var1 0 (1+ var1))) (quote (var2 0 (1+ var2))))

For which you could use the ' shorthand:

  (list '(var1 0 (1+ var1)) '(var2 0 (1+ var2)))

  ==>  ((VAR1 0 (1+ VAR1)) (VAR2 0 (1+ VAR2)))

> ;---------------------------------------------------------------------
> ; But the following results in an endless loop in CLISP and LISPWORKS
> ; and I'm yet to figure out why.

[ ... ]

>   (list                               ; explicitly declare the list
>     (= 10 varsum)                     ; the evaluated end-test form
>     (incf varsum)                     ; an evaluated result-form
>     (print varsum)                    ; an evaluated result-form
>     varsum)                           ; the returned result-form

Because you put the LIST variable as your END-TEST-FORM!!! And LIST is
set to NIL and never touched, so the END-TEST-FORM never becomes true.

DO is doing exactly what you told it to ``do''. You defined the VAR
form LIST, didn't give it any initial value, and then used it as the
END-TEST-FORM.