Can someone please explain why the finally clause below doesn't execute
after normal iteration terminates:
(loop for i from 1 to 10
collect i
finally collect 11)
returns:
(1 11 2 11 3 11 4 11 5 11 6 11 7 11 8 11 9 11 10 11)
Which is no different than:
(loop for i from 1 to 10
collect i
collect 11)
Is it just not possible to collect final values in the loop epilogue?
Thanks,
Adam
Adam> (loop for i from 1 to 10
Adam> collect i
Adam> finally collect 11)
Adam> returns:
Adam> (1 11 2 11 3 11 4 11 5 11 6 11 7 11 8 11 9 11 10 11)
Adam> Which is no different than:
Adam> (loop for i from 1 to 10
Adam> collect i
Adam> collect 11)
After a FINALLY you have to put a compound-form (a Lisp expression,
rather than a LOOP keyword), except that you are getting faked out
because you know that RETURN is allowed there (as a special case).
The consequences of the code FINALLY COLLECT are undefined, but your
implementation (CLISP I bet) happens to handle this by just totally
ignoring the bogus FINALLY clause.
Adam> Is it just not possible to collect final values in the loop epilogue?
(loop for i from 1 to 10 collecting i into foo
finally return (nconc foo '(11)))
> Hi all,
>
> Can someone please explain why the finally clause below doesn't execute
> after normal iteration terminates:
>
> (loop for i from 1 to 10
> collect i
> finally collect 11)
Read the Spec - finally is followed by a "compound form"
compound form n. a non-empty list which is a form: a special form, a
lambda form, a macro form, or a function form.
the collect clause is not a compound form!
> returns:
> (1 11 2 11 3 11 4 11 5 11 6 11 7 11 8 11 9 11 10 11)
>
> Which is no different than:
>
> (loop for i from 1 to 10
> collect i
> collect 11)
>
> Is it just not possible to collect final values in the loop epilogue?
Well what you actually tried to do is more like
(loop for i from 1 to 10
collect i into nums
finally (return (nconc nums (list i))))
But I'm not sure if accessing i in the finally clause actually should lead
to a 10 or an 11 at the end of the list. I've tried to check it in the
HyperSpec but did not find something about that.
Actually it would be probably more safe to do
(loop for i from 1 to (1+ 10) collect i)
If you want to collect one further step.
ciao,
Jochen
--
http://www.dataheaven.de
>>>>>> On Sat, 14 Sep 2002 15:10:06 +1200, Adam Warner ("Adam") writes:
> Adam> Hi all,
> Adam> Can someone please explain why the finally clause
> Adam> below doesn't execute after normal iteration terminates:
>
> Adam> (loop for i from 1 to 10
> Adam> collect i
> Adam> finally collect 11)
>
> Adam> returns:
> Adam> (1 11 2 11 3 11 4 11 5 11 6 11 7 11 8 11 9 11 10 11)
>
> Adam> Which is no different than:
>
> Adam> (loop for i from 1 to 10
> Adam> collect i
> Adam> collect 11)
>
> After a FINALLY you have to put a compound-form (a Lisp expression,
> rather than a LOOP keyword), except that you are getting faked out
> because you know that RETURN is allowed there (as a special case).
>
> The consequences of the code FINALLY COLLECT are undefined, but your
> implementation (CLISP I bet) happens to handle this by just totally
> ignoring the bogus FINALLY clause.
Many thanks Christopher and Jochen. You're right it is CLISP and I would
have learned a lot faster if it had signalled an error on the bogus clause.
> Adam> Is it just not possible to collect final values in the loop epilogue?
>
> (loop for i from 1 to 10 collecting i into foo
> finally return (nconc foo '(11)))
Thanks. I had already done this (the last item isn't supposed to be a
constant like the example above):
(nconc
(loop ...)
(list foo-last))
It turns out to be clearer and less verbose than the loop way!:
(nconc (loop for i from 1 to 10 collect i)
'(11))
Regards,
Adam
I see no such special case in the standard, only compound-forms.
--
Erik Naggum, Oslo, Norway
Act from reason, and failure makes you rethink and study harder.
Act from faith, and failure makes you blame someone and push harder.
> (loop for i from 1 to 10
> collect i
> finally collect 11)
This is very questionable. finally takes *forms* not clauses (as does
initially), so what you've actually written is probably interpreted as
if you'd said:
(loop for i from 1 to 10
collect i
finally nil
collect 11)
But if I was implementing LOOP I would signal, at least, a warning in
this case.
> Is it just not possible to collect final values in the loop epilogue?
Not the way you are trying to do it, no.
--tim
> After a FINALLY you have to put a compound-form (a Lisp expression,
> rather than a LOOP keyword), except that you are getting faked out
> because you know that RETURN is allowed there (as a special case).
No, it is not, not in the standard, anyway.
--tim
Erik> * Christopher C. Stacy
Erik> | After a FINALLY you have to put a compound-form (a Lisp expression,
Erik> | rather than a LOOP keyword), except that you are getting faked out
Erik> | because you know that RETURN is allowed there (as a special case).
Erik> I see no such special case in the standard, only compound-forms.
Hmm, I think you're probably right about that, but I was thinking
about the language in 6.1.7.2 talks about "Clauses such as return,..."
followed by "Such an explicit return inside the finally clause..."
which makes it sound like there is some special hack for FINALLY RETURN.
The BNF definitely agrees with you that there is no such hack, so that
ought to settle it. But the above language is a little bit confusing.
initial-final::= initially compound-form+ | finally compound-form+
Chris
Erik Naggum
> I see no such special case in the standard, only compound-forms.
Christopher C. Stacy
> Hmm, I think you're probably right about that, but I was thinking
> about the language in 6.1.7.2 talks about "Clauses such as return,..."
> followed by "Such an explicit return inside the finally clause..."
> which makes it sound like there is some special hack for FINALLY RETURN.
>
> The BNF definitely agrees with you that there is no such hack, so that
> ought to settle it. But the above language is a little bit confusing.
>
> initial-final::= initially compound-form+ | finally compound-form+
The first return is the return loop clause. The second is the return macro.
So this case is unambiguous.
--
"Die ganzen Zahlen hat der liebe Gott gemacht; alles andere ist Menschenwerk."
"God made the integers; all else is the work of man."
-- Leopold Kronecker (1821-1891)
> No, it is not, not in the standard, anyway.
On the subject of standard LOOP vs desires, I would like to be able to
concatenate iteration sequences. E.g. (loop as x in '(a b c) then
from 1 to 3 then in '(d e f) collect x) ==> (a b c 1 2 3 d e f).
Would there be any easy way for me to add such a feature, or is there
already such a feature I don't know about?
(loop nconc (loop for x in '(a b c) collect x)
nconc (loop for x from 1 to 3 collect x)
nconc (loop for x in '(d e f) collect x)
until t)
Is this what you are looking for?
Consider a function `range´
(defun range (from to)
(loop for i from from to to collect i))
You could use it like this:
(loop for x in `(a b c ,@(range 1 3) d e f) ...).
> (nconc (loop for i from 1 to 10 collect i)
> '(11))
And I just want to explain how I have reaffimed my understanding that this
is not safe practice.
Let's define the above as a function and then call it twice:
(defun dumb-loop ()
(nconc (loop for i from 1 to 10 collect i)
'(11)))
[2]> (dumb-loop)
(1 2 3 4 5 6 7 8 9 10 11)
[3]> (dumb-loop)
(1 2 3 4 5 6 7 8 9 10 11)
That's fine. But this time let's do some destructive modification on
the output:
[6]> (nconc (dumb-loop) '(12))
(1 2 3 4 5 6 7 8 9 10 11 12)
[7]> (nconc (dumb-loop) '(12))
(1 2 3 4 5 6 7 8 9 10 11 12 12)
Oh no! dumb-loop, which you expect to be a list of 11 numbers is
returning a different result each time.
You can no longer rely upon the quoted 11 to be 11 any more. It is
destructively modified when linking the lists together, but this only
becomes apparent when it is no longer the last term in the list
construction.
I suggest the above loop should at least have been coded this way:
(nconc (loop for i from 1 to 10 collect i)
(list 11))
Which agrees with Timothy Moore's recent comment in another thread: "That
quoted list is constant. If you're going to fool around with nconc (and I
don't see what you find so distasteful about the use of append) better
try (nconc list (list 'element))."
Regards,
Adam
>> (nconc (loop for i from 1 to 10 collect i)
>> '(11))
>
> I suggest the above loop should at least have been coded this way:
>
> (nconc (loop for i from 1 to 10 collect i)
> (list 11))
Frankly, I would just have avoided the whole issue by writing
it this way:
(loop for i from 1 to 11 collect i)
> (loop nconc (loop for x in '(a b c) collect x)
> nconc (loop for x from 1 to 3 collect x)
> nconc (loop for x in '(d e f) collect x)
> until t)
And Erik Naggum wrote:
> (loop for x in `(a b c ,@(range 1 3) d e f) ...).
Both of those solve the problem in my example, but it was intended to
be an example of a more general problem. There are often situations
where the first iteration or two, and/or the last iteration or two, of
a long sequence which might run in parallel with other long sequences
in the same loop, need something special. As it is now, the code to
handle those special cases can make the whole loop form longer and
messier. It would be nice to find some completely general way to tell
it to iterate through one sequence and then another and then another,
without sacrificing any of the other features or conveniences of loop.
Thanks for letting me sample your wit here and via email Steven ;-)
The issue was adding a final term to a list. As I wrote earlier in
the thread:
Thanks. I had already done this (the last item isn't supposed to be a
constant like the example above):
(nconc
(loop ...)
(list foo-last))
I provided the note on the effect of using nconc & quoted values for the
benefit of people learning Lisp. By your humorous rationale I could have
avoided the whole issue of using loop by writing:
(reverse (maplist #'length (make-sequence 'list 11)))
Regards,
Adam
Both solutions were, I think, intended to solve the more general problem,
but I now see that your major gripe is not the loss of features of `loop´,
but consing up a brand new list, and this is a more valid concern in my
view. The even more general problem than we solved would thus be a case
such as
(loop for code from 32 to 95 then from 160 to 255
do (... something with ISO 8-bit character set conventsions ...))
which would certainly be more convenient than, say,
(loop for code from 32 to 255
unless (< 95 code 160) ...)
So I am sympathetic to your request now that I understand your goal better.
The `loop´ macro is normally supplied in source form with your Common Lisp
implementation, so it should be possible to modify it locally, with all the
drawbacks that has. I concur that some community effort to define such a
mechanism would be useful, and it should be addable without serious
compatibility problems because `then´ is not a valid clause.
> On the subject of standard LOOP vs desires, I would like to be able to
> concatenate iteration sequences. E.g. (loop as x in '(a b c) then
> from 1 to 3 then in '(d e f) collect x) ==> (a b c 1 2 3 d e f).
Yes, I've wanted this - particularly something like:
(loop for x in '(1 2 3) then from 1 to 10 then on '(1 2 3) ...)
I don't think that there is a standard way of doing this other than
simply doing something to create an object with is the `concatenation'
of all these things. Some versions of LOOP have a way of defining new
clauses, so one could probably use that to define something like this
(I'm not sure if you could use `for' though?).
--tim
it is not a valid preposition.
--
Janos Blazi
-----------== Posted via Newsfeed.Com - Uncensored Usenet News ==----------
http://www.newsfeed.com The #1 Newsgroup Service in the World!
-----= Over 100,000 Newsgroups - Unlimited Fast Downloads - 19 Servers =-----
Well, I trolled and hooked you, so now I'll give some serious advice.
;-)
(Digression: I learned just this weekend that Scott Fahlman, one of the
CLtL1 Gang of Five, and a productive member of X3J13, Chair of the
"Cleanup Committee", is believed to be the inventor of the ":-)"
emoticon. See http://news.com.com/2100-1023-957817.html?tag=fd_top )
When X3J13 adopted the LOOP macro, it was a devisive and contested
decision. There was a subcommittee on iteration that did the study
of iteration system proposals. I vaguely remember the vote was only
something like 60/40. Most X3J13 decisions of such grand importance
were more-decisively for or against.
The argument against the non-simple LOOP was that it had irregular,
un-lispy syntax, was hard to read in complex cases, and therefore
didn't always do what the programmer expected. The argument in favor
was mostly that LOOP was well understood in practice, there was a lot
of existing code that used it, and that it was something that a
significant portion of practicing near-CL programmers would expect to
use in their code. The latter argument carried (and I was one voting
in favor). I personally use lloop, and like the kinds of things it
expresses concisely and eloquently. I also recursively macroexpand
any nontrivial loop I write before compiling to make sure it really
does what I think it does. So you can see that I agree with both
sides in the original dispute; but I think it is good to have
non-simple LOOP in the language, just like it is good to have format
strings. (Nearly every argument against LOOP can be applied verbatim
against format strings.)
But there were two other proposed iteration systems that contended
with the historical LOOP macro: One was Richard Waters' (or Pretty
Printer fame) "Series" package, and the other was "Generators and
Gatherers" by Waters and Crispin Purdue, which (IIRC) was a later
proposal based on experience with Series. Both were more Lispy
and functional than the macro swamp of LOOP.
Neither of these was adopted, although the committee generally felt
that both were technically, conceptually, linguistically, and
morally superior to LOOP. The difficulty (IIRC) was that there was
less experience using these systems, and perhaps they needed more
exercise and trials with efficient implementation before being
committed to the standard. The committee (IIRC) generally hoped that
these would be kept available in portable packages, and perhaps
optimized by implementors, so that they could be used and perhaps
later become a regular part of the langauge. They are not part of
the ANSI standard, but there are good writeups of these two packages
in CLtL2, appendixes A and B respectively.
I know that the series package is readily available on the web.
Check http://series.sourceforge.net/ and other standard places.
Anyway, I expect the kind of things you want to express are natural
and idiomatic in series.
Future versions of CLISP will give a warning about this code.
Bruno