[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.lisp

Re: CAR/CDR vs FIRST/REST [avoid LOOPiness]

William James

4/23/2015 4:03:00 PM

Barry Margolin wrote:

> > compare
> > (loop for x in list
> > collect (my-fcn x))
> > and
> > (loop for x in list
> > do (my-fcn x)
> > return list)
>
> Assuming the second one is supposed to be equivalent to (mapc #'my-fcn
> list), it has a bug: you forgot to say "finally" before the "return". If I
> were using LOOP instead of MAPC I'd almost always punt the return value;
> I've never actually seen anyone use the return value of MAPC.
>
> > with the equivalent map forms (I can't figure out what they'd be
> > with less than a few minutes study, but I think they're mapcar
> > and mapc?) Now try to argue that the latter are more readable
> > to the new reader, and that errors in coding are more
> > transparent with them. Go ahead, I'm listening. For my money,
> > the difference between the above loop forms is more apparent
> > than the mapc/mapcar typo will ever be.
>
> As I've already mentioned, the names of the mapping functions are horrible.
> Are you arguing against mapping functions in general, or just the current
> names? If MAPC were named MAP-LIST-ELEMENTS and MAPCAR were named
> MAP-LIST-ELEMENTS-RETURNING-RESULTS, would you still prefer LOOP over the
> mapping functions?
>
> And what about
>
> (dolist (x list)
> (my-fcn x))
>
> An advantage of this over the equivalent LOOP is that accidentally hitting
> "o" instead of "i" (which are adjacent on most keyboards, and thus an easy
> typo) doesn't result in a different, but still valid, form; compare this
> with:
>
> (loop for x on list
> do (my-fcn x))

Gauche Scheme:

gosh> (for-each print '(a b c))
a
b
c

gosh> (for-each print '(a b c) (lrange 1))
a1
b2
c3

gosh> (dolist (x '(a b c)) (print x))
a
b
c

gosh> (dotimes (3) (print 'ok))
ok
ok
ok


>
> It has only one character different from the correct form, but will have
> very different effects. The only two mapping functions that differ by only
> a letter are MAPCON and MAPCAN; they're rarely used, and harder to typo.
>
> > (mapcan #'(lambda (x) (and (numberp x) (list x))) list)
>
> > (loop for x in list
> > when (numberp x) collect x)
>
> I agree with this example. Once I learned LOOP I never used the above
> idiom again. I also never use


Gauche Scheme:

gosh> (filter number? '(a 2 c 4))
(2 4)



> (do ((result nil)
> ...)
> (<test> (nreverse result))
> ...
> (push <something> result)
> ...)
>
> Which was another common pre-LOOP idiom for collecting things into a list
> during an iteration.



gosh> (use srfi-1 :only (list-tabulate unfold))
gosh> (list-tabulate 8 square)
(0 1 4 9 16 25 36 49)
gosh> (unfold (cut = 8 <>) square (cut + 1 <>) 0)
(0 1 4 9 16 25 36 49)


gosh> (use srfi-42 :only (list-ec vector-ec))
gosh> (list-ec (:range i 8) (square i))
(0 1 4 9 16 25 36 49)
gosh> (list-ec (:range i 20) (if (odd? i)) (square i))
(1 9 25 49 81 121 169 225 289 361)
gosh> (vector-ec (:range i 2) (: c #\x #\z) (list i c))
#((0 #\x) (0 #\y) (0 #\z) (1 #\x) (1 #\y) (1 #\z))

gosh> (list-ec (:until (:generator x read) (eof-object? x)) x)
22 foo
^Z
(22 foo)

gosh> (list-ec (:port x (standard-input-port)) x)
22 foo
^Z
(22 foo)


gosh> (filter-map (^x (and (number? x) (square x))) '(2 a 3 4))
(4 9 16)


....

> As readable as many LOOP forms are, you have to admit that they're at a
> slightly lower level of abstraction than most of the alternatives. For
> instance, the programmer is required to provide a name for the iteration
> variable, when all he cares about is that the iteration object be passed to
> the iteration function somehow; the mapping functions and Waters's Series
> package make this argument passing implicit.
>
> I admit that the abstraction level between LOOP and the mapping functions
> are pretty close. However, in one of the messages in this thread someone
> (was it you?) suggested that LOOP be used instead of the sequence functions
> such as REMOVE. The sequence functions automatically work on both lists
> and vectors (I thought X3J13 had added a LOOP iterator that does this, but
> I was wrong -- all we added was the ACROSS iterator, which works on
> vectors). They don't require you to examine the logic of the loop body to
> determine how the result is derived from the input -- the name REMOVE is
> perfectly obvious (although the distinction between REMOVE and DELETE
> simply has to be memorized -- the Scheme folks' use of a standard suffix is
> much nicer, and a Common Lispy way to do it might have been to add a
> :DESTRUCTIVE keyword argument, but we're stuck with lots of MacLisp
> mistakes). My only real complaint about the sequence functions is that
> there's no KEEP-IF function; almost all my uses of REMOVE-IF-NOT (which is
> deprecated in ANSI CL, in favor of using REMOVE-IF and COMPLEMENT) are for
> this purpose, and I think it would be much easier to read if there were
> such a function.
>
> > 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!

....

> > Loop, in fact, easily does lots of things that _none_ of the
> > mapping and iteration forms do. Personally, I'm no great loop
> > hacker, and I never exercise most of the loop clauses available;
> > generally I use the small subset of loop keywords necessary to
> > implement the 9 forms listed above (< half a dozen), and rarely
> > use _finally_ or _minimizing_ or what-have-you forms. (Let's
> > try to keep the discussion rational.)
>
> If most people only wrote such simple loops, there would be no need for
> LOOP. It's much better to have special-case forms that indicate precisely
> what you're doing. Assuming the forms have reasonable names, this makes it
> easier for a reader to understand them. And whatever the names are, it
> makes it easier for the compiler to generate good code for them. I would
> never use LOOP when DOLIST or DOTIMES would do. The general forms like
> LOOP are for times when the simple forms aren't appropriate.


gosh> (until (read) eof-object? => x (print x))
22 foo bar
22
foo
bar
^Z


gosh> (let1 items '(aa bb cc)
(while (pair? items) (print (pop! items))))
aa
bb
cc
1 Answer

William James

4/24/2015 5:58:00 AM

0


Thomas A. Russ wrote:

> (loop for x in list
> do (my-fcn x)
> return list)
>
> with the equivalent map forms...
>
> The latter example doesn't do what you think it does. It will call
> MY-FCN on the first element of LIST, and then return LIST. To be
> equivalent to mapc, it needs to be:
>
> (loop for x in list
> do (my-fcn x)
> FINALLY (return list))
>
> with the return in parentheses!

Again, we see that users of LOOP are the worst "programmers"
in the world.