Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.lisp > #60334 > unrolled thread
| Started by | "B. Pym" <Nobody447095@here-nor-there.org> |
|---|---|
| First post | 2025-06-18 10:20 +0000 |
| Last post | 2025-08-25 08:38 +0000 |
| Articles | 4 — 2 participants |
Back to article view | Back to comp.lang.lisp
Re: Am I missing something about (loop ... maximizing ...) ? "B. Pym" <Nobody447095@here-nor-there.org> - 2025-06-18 10:20 +0000
Re: Am I missing something about (loop ... maximizing ...) ? "B. Pym" <Nobody447095@here-nor-there.org> - 2025-08-25 08:28 +0000
Re: Am I missing something about (loop ... maximizing ...) ? tpeplt <tpeplt@gmail.com> - 2025-08-25 18:03 -0400
Re: Am I missing something about (loop ... maximizing ...) ? "B. Pym" <Nobody447095@here-nor-there.org> - 2025-08-25 08:38 +0000
| From | "B. Pym" <Nobody447095@here-nor-there.org> |
|---|---|
| Date | 2025-06-18 10:20 +0000 |
| Subject | Re: Am I missing something about (loop ... maximizing ...) ? |
| Message-ID | <102u3to$32kl5$1@dont-email.me> |
Raffael Cavallaro wrote:
> Indeed. Here's rob Warnock's version with the full boat of loop
> keywords using triplets instead of an association list:
>
> CL-USER 22 > (defun find-maximizing-item (list &key (key #'identity)
> (test #'<))
> (loop for item in list
> for value = (funcall key item)
> and position from 0
> for current-triplet = (list item value position)
> as max-triplet = current-triplet
> then (if (funcall test (second max-triplet)
> (second current-triplet))
> current-triplet
> max-triplet)
> finally return
> (values (first max-triplet) (second max-triplet)
> (third max-triplet))))
Rejected by ABCL:
Debugger invoked on condition of type PROGRAM-ERROR:
Current LOOP context: "A compound form was expected, but ~S found.".
Rejected by SBCL:
; in: LAMBDA NIL
; (LOOP FOR ITEM IN LIST
; FOR VALUE = (FUNCALL KEY ITEM)
; AND POSITION FROM ...)
;
; caught ERROR:
; (in macroexpansion of (LOOP FOR ITEM ...))
; (hint: For more precise location, try *BREAK-ON-SIGNALS*.)
; A compound form was expected, but RETURN found.
; current LOOP context: FINALLY RETURN (VALUES (FIRST MAX-TRIPLET)
; (SECOND MAX-TRIPLET)
; (THIRD MAX-TRIPLET)).
> FIND-MAXIMIZING-ITEM
>
> CL-USER 28 > (find-maximizing-item (list "one" "two" "three" "fifteen"
> "four" "five") :key #'length)
> "fifteen"
> 7
> 3
It's somewhat shorter in Gauche Scheme.
(use gauche.collection) ;; find-max
(define (find-maximizing-item items :optional (key identity))
(find-max
(map (lambda (x i) (list x (key x) i)) items (liota))
:key cadr))
(find-maximizing-item (list "one" "two" "three" "fifteen" "four"
"five") string-length)
===>
("fifteen" 7 3)
[toc] | [next] | [standalone]
| From | "B. Pym" <Nobody447095@here-nor-there.org> |
|---|---|
| Date | 2025-08-25 08:28 +0000 |
| Message-ID | <108h6qk$3aant$1@dont-email.me> |
| In reply to | #60334 |
B. Pym wrote:
> Raffael Cavallaro wrote:
>
> > Indeed. Here's rob Warnock's version with the full boat of loop
> > keywords using triplets instead of an association list:
> >
> > CL-USER 22 > (defun find-maximizing-item (list &key (key #'identity)
> > (test #'<))
> > (loop for item in list
> > for value = (funcall key item)
> > and position from 0
> > for current-triplet = (list item value position)
> > as max-triplet = current-triplet
> > then (if (funcall test (second max-triplet)
> > (second current-triplet))
> > current-triplet
> > max-triplet)
> > finally return
> > (values (first max-triplet) (second max-triplet)
> > (third max-triplet))))
>
>
> Rejected by ABCL:
>
> Debugger invoked on condition of type PROGRAM-ERROR:
>
> Current LOOP context: "A compound form was expected, but ~S found.".
>
>
> Rejected by SBCL:
>
> ; in: LAMBDA NIL
> ; (LOOP FOR ITEM IN LIST
> ; FOR VALUE = (FUNCALL KEY ITEM)
> ; AND POSITION FROM ...)
> ;
> ; caught ERROR:
> ; (in macroexpansion of (LOOP FOR ITEM ...))
> ; (hint: For more precise location, try *BREAK-ON-SIGNALS*.)
> ; A compound form was expected, but RETURN found.
> ; current LOOP context: FINALLY RETURN (VALUES (FIRST MAX-TRIPLET)
> ; (SECOND MAX-TRIPLET)
> ; (THIRD MAX-TRIPLET)).
>
>
>
> > FIND-MAXIMIZING-ITEM
> >
> > CL-USER 28 > (find-maximizing-item (list "one" "two" "three" "fifteen"
> > "four" "five") :key #'length)
> > "fifteen"
> > 7
> > 3
Gauche Scheme
"!" is similar to "do".
(define (maximize List :optional (key identity))
(! (x :in List
i 0 +
best #f (list x val i) :if (or (not best) (> val (cadr best)))
val #f)
(not x) best
(set! val (key x))))
(maximize '("bells" "usher" "ullalume" "poe") string-length)
===>
("ullalume" 8 2)
Given:
(define-syntax !-aux
(syntax-rules (<> @ + - cons cdr :in :across :if ! )
[(_ (:if bool z ...) (seen ... (v i u)) stuff ...)
(!-aux (z ...)
(seen ... (v i (if bool u v))) stuff ...) ]
[(_ (x :in lst z ...) seen (lets ...) stuff ...)
(!-aux (x (and (pair? xs)(pop! xs)) <> z ...)
seen (lets ... (xs lst)) stuff ...) ]
[(_ (x :across vec z ...) seen (lets ...) stuff ...)
(!-aux (x (and (< i (vector-length v))
(begin0 (vector-ref v i) (inc! i))) <>
z ...)
seen (lets ... (v vec) (i 0)) stuff ...) ]
[(_ (a b <> z ...) (seen ...) stuff ...)
(!-aux (z ...) (seen ... (a b b)) stuff ...) ]
[(_ (a b + z ...) (seen ...) stuff ...)
(!-aux (z ...) (seen ... (a b (+ 1 a))) stuff ...) ]
[(_ (a + n z ...) (seen ...) stuff ...)
(!-aux (z ...) (seen ... (a 0 (+ n a))) stuff ...) ]
[(_ (a b - z ...) (seen ...) stuff ...)
(!-aux (z ...) (seen ... (a b (- a 1))) stuff ...) ]
[(_ (a cons b z ...) (seen ...) stuff ...)
(!-aux (z ...) (seen ... (a '() (cons b a))) stuff ...) ]
[(_ (a b cdr z ...) (seen ...) stuff ...)
(!-aux (z ...) (seen ... (a b (cdr a))) stuff ...) ]
[(_ (a b c z ...) (seen ...) stuff ...)
(!-aux (z ...) (seen ... (a b c)) stuff ...) ]
[(_ (a b) (seen ...) stuff ...)
(!-aux () (seen ... (a b)) stuff ...) ]
[(_ (a) (seen ...) stuff ...)
(!-aux () (seen ... (a '())) stuff ...) ]
;;
[(_ () seen lets a b c ! action ...)
(!-aux () seen lets (a b c) #t (action ...)) ]
[(_ () seen lets a b ! action ...)
(!-aux () seen lets (a b) #t (action ...)) ]
[(_ () seen lets a ! action ...)
(!-aux () seen lets a #t (action ...)) ]
;;
[(_ () ((a b c) z ...) lets bool)
(!-aux () ((a b c) z ...) lets bool a) ]
[(_ () ((a b c) z ...) lets bool @)
(!-aux () ((a b c) z ...) lets bool (reverse a)) ]
[(_ () seen lets bool @ result stuff ...)
(!-aux () seen lets bool (reverse result) stuff ...) ]
[(_ () seen lets bool (what @ x z ...) stuff ...)
(!-aux () seen lets bool (what (reverse x) z ...) stuff ...) ]
[(_ () seen lets bool (what x @ y z ...) stuff ...)
(!-aux () seen lets bool (what x (reverse y) z ...) stuff ...) ]
[(_ () ((a b c) z ...) lets 0 stuff ...)
(!-aux () ((a b c) z ...) lets (= 0 a) stuff ...) ]
[(_ () seen lets bool result stuff ...)
(let lets (do seen (bool result) stuff ...)) ]
))
(define-syntax !
(syntax-rules ()
[(_ specs bool stuff ...)
(!-aux specs () () bool stuff ...) ]
))
--
[T]he problem is that lispniks are as cultish as any other devout group and
basically fall down frothing at the mouth if they see [heterodoxy].
--- Kenny Tilton
The good news is, it's not Lisp that sucks, but Common Lisp. --- Paul Graham
[toc] | [prev] | [next] | [standalone]
| From | tpeplt <tpeplt@gmail.com> |
|---|---|
| Date | 2025-08-25 18:03 -0400 |
| Message-ID | <87tt1vys79.fsf@gmail.com> |
| In reply to | #60665 |
> B. Pym wrote:
>
>> Raffael Cavallaro wrote:
>>
>> > Indeed. Here's rob Warnock's version with the full boat of loop
>> > keywords using triplets instead of an association list:
>> >
>> > CL-USER 22 > (defun find-maximizing-item (list &key (key #'identity)
>> > (test #'<))
>> > (loop for item in list
>> > for value = (funcall key item)
>> > and position from 0
>> > for current-triplet = (list item value position)
>> > as max-triplet = current-triplet
>> > then (if (funcall test (second max-triplet)
>> > (second current-triplet))
>> > current-triplet
>> > max-triplet)
>> > finally return
>> > (values (first max-triplet) (second max-triplet)
>> > (third max-triplet))))
>>
>>
>> Rejected by ABCL:
>>
>> Debugger invoked on condition of type PROGRAM-ERROR:
>>
>> Current LOOP context: "A compound form was expected, but ~S found.".
>>
>>
>> Rejected by SBCL:
>>
The function definition is missing a single pair of
parentheses in the ‘finally’ clause.
finally return
(values (first max-triplet) (second max-triplet)
(third max-triplet))
should be changed to:
finally (return
(values (first max-triplet)
(second max-triplet)
(third max-triplet))
See:
http://www.ai.mit.edu/projects/iiip/doc/CommonLISP/HyperSpec/Body/sec_6-1-1-6.html
* The code for any FINALLY clauses is collected into one
PROGN in the order in which the clauses appear in the
source. The collected code is executed once in the loop
epilogue before any implicit values from the accumulation
clauses are returned. Explicit returns anywhere in the
source, however, will exit the loop without executing the
epilogue code.
Since the code in the FINALLY clause is collected into an
implicit PROGN, the code is required to be Lisp expressions,
instead of LOOP clauses, which rules out the use of the LOOP
keyword RETURN.
With the change described above, the function works as
expected on the tests below:
(find-maximizing-item
(list "one" "two" "three" "fifteen" "four" "five") :key #'length)
;;=> "fifteen"
;;=> 7
;;=> 3
(find-maximizing-item '("bells" "usher" "ullalume" "poe") :key #'length)
;;=> "ullalume"
;;=> 8
;;=> 2
--
The lyf so short, the craft so long to lerne.
- Geoffrey Chaucer, The Parliament of Birds.
[toc] | [prev] | [next] | [standalone]
| From | "B. Pym" <Nobody447095@here-nor-there.org> |
|---|---|
| Date | 2025-08-25 08:38 +0000 |
| Message-ID | <108h7e6$3aenc$1@dont-email.me> |
| In reply to | #60334 |
B. Pym wrote: > Raffael Cavallaro wrote: > > > Indeed. Here's rob Warnock's version with the full boat of loop > > keywords using triplets instead of an association list: > > > > CL-USER 22 > (defun find-maximizing-item (list &key (key #'identity) > > (test #'<)) > > (loop for item in list > > for value = (funcall key item) > > and position from 0 > > for current-triplet = (list item value position) > > as max-triplet = current-triplet > > then (if (funcall test (second max-triplet) > > (second current-triplet)) > > current-triplet > > max-triplet) > > finally return > > (values (first max-triplet) (second max-triplet) > > (third max-triplet)))) > > > Rejected by ABCL: > > Debugger invoked on condition of type PROGRAM-ERROR: > > Current LOOP context: "A compound form was expected, but ~S found.". > > > Rejected by SBCL: > > ; in: LAMBDA NIL > ; (LOOP FOR ITEM IN LIST > ; FOR VALUE = (FUNCALL KEY ITEM) > ; AND POSITION FROM ...) > ; > ; caught ERROR: > ; (in macroexpansion of (LOOP FOR ITEM ...)) > ; (hint: For more precise location, try *BREAK-ON-SIGNALS*.) > ; A compound form was expected, but RETURN found. > ; current LOOP context: FINALLY RETURN (VALUES (FIRST MAX-TRIPLET) > ; (SECOND MAX-TRIPLET) > ; (THIRD MAX-TRIPLET)). Paul Graham: I consider Loop one of the worst flaws in CL, and an example to be borne in mind by both macro writers and language designers. [In "ANSI Common Lisp", Graham makes the following comments:] The loop macro was originally designed to help inexperienced Lisp users write iterative code. Instead of writing Lisp code, you express your program in a form meant to resemble English, and this is then translated into Lisp. Unfortunately, loop is more like English than its designers ever intended: you can use it in simple cases without quite understanding how it works, but to understand it in the abstract is almost impossible. .... the ANSI standard does not really give a formal specification of its behavior. .... The first thing one notices about the loop macro is that it has syntax. A loop expression contains not subexpressions but clauses. The clauses are not delimited by parentheses; instead, each kind has a distinct syntax. In that, loop resembles traditional Algol-like languages. But the other distinctive feature of loop, which makes it as unlike Algol as Lisp, is that the order in which things happen is only loosely related to the order in which the clauses occur. .... For such reasons, the use of loop cannot be recommended. Dan Weinreb, one of the designers of Common Lisp: ... the problem with LOOP was that it turned out to be hard to predict what it would do, when you started using a lot of different facets of LOOP all together. This is a serious problem since the whole idea of LOOP was to let you use many facets together; if you're not doing that, LOOP is overkill. Barry Margolin: My recommendation is based on seeing many question in the past of the form "What happens if you use both XXX and YYY in the same LOOP?" The unfortunate fact is that when we were writing the standard we didn't have time to nail down all the possible interactions between different LOOP features, so many of these are not well specified. And even if we did get it right in the standard, it's likely to be difficult to find them and I wouldn't trust that all implementors got it right (many of those questions were probably from implementors, trying to figure out what they were supposed to do). And even if they all got it right, someone reading your code may not be able to figure it out. So, with all those potential problems, my feeling is that if you have to ask, it's probably better to use something other than LOOP. Barry Margolin: > 3. Loop is very powerful, granted, and many people are trying to > argue that "you can do so much with loop that it's unreadable." > This is not an argument. But it is! Because any use of LOOP has the potential to be unreadable, the reader must read it carefully to verify that it's just one of the cases that doesn't require careful reading! Barry Margolin (1997-01-08) There are a few things that can be done extremely conveniently with LOOP, and I will usually use LOOP in those cases. In particular, the COLLECTING feature is one of the most convenient. The Generators and Collectors macros described in Appendix B of CLtL2 also provide this convenience and are much more Lisp-like. It's too bad they weren't around when LOOP was gaining popularity, and I think they're a better way to go. But LOOP is what I got used to, and its popularity is why it got elevated into the ANSI standard. Barry Margolin: (05 Apr 2002 20:57:48 GMT) This seems like a big change just to clean up the way LOOP is described. And LOOP will still be a wart, because it will be the only language feature that uses "per-macro keywords". Providing this interface and giving a name to them would encourage other macro designers to do something similar, and we don't want more things like LOOP. John Foderaro: I'm not trying to join a debate on loop. I just wanted to present the other side of [the issue so that] the intelligent people can then weigh the arguments on both sides. I'm not suggesting that loop can be fixed either by adding parenthesis or coming up with ways of indenting it to make it understandable. It's a lost cause. ... Another great example from kmp: === from kmp For example, you might think (loop with i = (random 100) for x from 1 to 10 do (print (list i x))) and (loop for i = (random 100) for x from 1 to 10 do (print (list i x))) meant the same in English, [but they don't do the same thing in loop] === end kmp loop lulls you into thinking that you understand the program since you understand English. Make no mistake about it, loop is its own language. If you use it you condemn everyone who reads the code to also learn the loop language. -- [T]he problem is that lispniks are as cultish as any other devout group and basically fall down frothing at the mouth if they see [heterodoxy]. --- Kenny Tilton The good news is, it's not Lisp that sucks, but Common Lisp. --- Paul Graham
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.lisp
csiph-web