#|
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?
|#
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.
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.