Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

MAP (and variants) vs LOOP - Popular opinion observation?

39 views
Skip to first unread message

Jonathon McKitrick

unread,
Aug 2, 2006, 7:17:40 PM8/2/06
to

It seems to me that popular opinion leans toward LOOP in favor of map
and variants where either would apply, for the following reasons, to
mention a few:

1. LOOP is more readable
2. LOOP is more efficient
3. LOOP forms are more easily modified and expanded

Are these the main reasons, or are there others? Any to the contrary?

ajones

unread,
Aug 2, 2006, 7:23:35 PM8/2/06
to

You know, I have done next to no Lisp programming (still working my way
through PCL) and I have to say that, at the moment, I hate loop. I
should love it, it handles pretty much every looping mechanism under
the sun, but is not brain dead like the rest of them are. In thinking
about it though, I have the same problem with the *other* Lisp
mini-language (format), so maybe it is just my brain rejecting the
concept of trying to learn three languages at once.

nall...@gmail.com

unread,
Aug 2, 2006, 8:06:34 PM8/2/06
to

I would argue that LOOP forms are less visually intuitive.

jkf's "Lisp Coding Standards v1.0" [1] says it well:

"Use do, dotimes and dolist for iteration in place of the extended loop
macro (the one using the keywords). The structure of the code inside
a loop is not apparent. Thus a function with loop in it is opaque
until you've read carefully through all the keywords used in the
expression."

personally I prefer map and variants to the DO or LOOP families...

Nick

(1) http://www.franz.com/~jkf/coding_standards.html

Ken Tilton

unread,
Aug 2, 2006, 8:12:44 PM8/2/06
to

- Loop is more concise. Related: I do not have to type l-a-m-b-d-a. I
hate typing l-a-m-b-d-a.

- You missed a rather huge difference: ...no, this is not a bullet. We
return to prose mode...

You cannot compare map* and loop. Loop is an iteration language, with
many bells and whistles. Map*s just map.

kt

--
Cells: http://common-lisp.net/project/cells/

"I'll say I'm losing my grip, and it feels terrific."
-- Smiling husband to scowling wife, New Yorker cartoon

Ken Tilton

unread,
Aug 2, 2006, 8:19:21 PM8/2/06
to

Yeah, took me forever (and PCL) before I broke down and sorted out the
unpredictable syntax, but now I do not use anything

Yeah, took me forever and a PCL before I broke down and learned loop.
Big mistake. Iteration is so common in code, it is worth the trouble. I
am still not that great at format, but I do not use it much and now at
least I know what is there in case I need to write out the lyrics to 99
Beers On the Wall.

My2: Learn loop now. Just a coupla hours with PCL should do it.

Pascal Bourguignon

unread,
Aug 2, 2006, 8:33:18 PM8/2/06
to
"Jonathon McKitrick" <j_mck...@bigfoot.com> writes:

> It seems to me that popular opinion leans toward LOOP in favor of map
> and variants where either would apply, for the following reasons, to
> mention a few:
>
> 1. LOOP is more readable

Depends of your frame.


> 2. LOOP is more efficient

Depends on the compiler.


> 3. LOOP forms are more easily modified and expanded

Not always.


> Are these the main reasons, or are there others? Any to the contrary?

One advantage of map* is that you can easily build them step by step
at the REPL:

(mapcar (lambda (x) (some-processing x)) data)

then when the output is what you expect,

(mapcar (lambda (x) (some-more-processing x))
(mapcar (lambda (x) (some-processing x)) data))

then some more:

(mapcar (lambda (x) (some-very-more-processing x))
(mapcar (lambda (x) (some-more-processing x))
(mapcar (lambda (x) (some-processing x)) data)))

etc. This "filter" frame can be more natural than a loop some times.
(But frankly, in general I eventually rewrite them as LOOPs, once
bottom-up'ed).


Also, when you have a parallel processor (MMX, SSE, Altivec, etc),
it's easier for the compilers to optimize MAP* than LOOP.


--
__Pascal Bourguignon__ http://www.informatimago.com/

"Do not adjust your mind, there is a fault in reality"
-- on a wall many years ago in Oxford.

Pascal Costanza

unread,
Aug 3, 2006, 4:51:31 AM8/3/06
to

mapcar and mapc are pretty useful when the function you want to map is
already defined (or needs to be defined) anyway, because (mapcar
#'foobar some-list) or (mapc #'foobar some-list) is pretty concise.
However, when it gets more complicated than that, I tend to switch to LOOP:

- When you have to build an anonymous function for mapcar, LOOP
typically uses the same number of source code lines, and seems clearer
to me. Compare:

(mapcar (lambda (x) ... do something with x ...)
some-list)

(loop for x in some-list
collect ... do something with x ...)

- I don't remember having used functions with more than one argument in
conjunction with mapcar, so it seems to me that (mapcar #'foobar
some-list1 some-list2) [or even more lists] is pretty uncommon. Again,
if you need to build an anonymous function with more than one arguments,
LOOP seems clearer to me:

(mapc (lambda (x y) ...)
some-list1 some-list2)

(loop for x in some-list1
for y in some-list2
do ...)

- More often than not, the different variables actually iterate over
different kinds of values. Recently, I needed the following costruct
quite often:

(loop for x in some-list
for i from 0
collect `(,x ,i))

This enumerates all elements in a list. You would have to express this
completely manually without LOOP because none of the mapxyz functions
help you here.

- The mapcan idiom to filter out certain elements is, IMHO, a hack. Compare:

(mapcan (lambda (x)
(when (some-property-p x)
(list x)))
some-list)

(loop for x in some-list
when (some-property-p x)
collect x)

In this case, LOOP is more concise, and more importantly more explicit
about what it actually does. To me, that's in fact the most important
advantage of LOOP - it typically tells you what it does in a way that is
almost close to natural language.


Pascal

--
My website: http://p-cos.net
Closer to MOP & ContextL:
http://common-lisp.net/project/closer/

Lars Brinkhoff

unread,
Aug 3, 2006, 6:28:56 AM8/3/06
to
Pascal Costanza <p...@p-cos.net> writes:
> I don't remember having used functions with more than one argument
> in conjunction with mapcar, so it seems to me that (mapcar #'foobar
> some-list1 some-list2) is pretty uncommon.

In one of my programs 2% of the calls to mapcar used more than one
list argument. E.g:

(mapcar #'list syms '#1=((gensym) . #1#))

That seems quite concise (if perhaps not entirely crystal clear, in
this case) to me.

> - The mapcan idiom to filter out certain elements is, IMHO, a hack. Compare:
>
> (mapcan (lambda (x)
> (when (some-property-p x)
> (list x)))
> some-list)
>
> (loop for x in some-list
> when (some-property-p x)
> collect x)

I would think that remove-if-not (or remove-if) is usually better than
this mapcan idiom. Maybe even competetive with loop.

(Not arguing against loop. I like loop.)

Tayssir John Gabbour

unread,
Aug 3, 2006, 9:17:40 AM8/3/06
to
Lars Brinkhoff wrote:

> Pascal Costanza <p...@p-cos.net> writes:
> > (mapcan (lambda (x)
> > (when (some-property-p x)
> > (list x)))
> > some-list)
> >
> > (loop for x in some-list
> > when (some-property-p x)
> > collect x)
>
> I would think that remove-if-not (or remove-if) is usually better than
> this mapcan idiom. Maybe even competetive with loop.
>
> (Not arguing against loop. I like loop.)

I sometimes think remove-if-not would be used even more if named
something like 'keep', or SICP's 'filter'. Because there's something
double negative-ish about it.

Tayssir

Pascal Costanza

unread,
Aug 3, 2006, 9:36:03 AM8/3/06
to

Hmm, I rather think that remove-if-not is too unstable, in the following
sense: When I say, for example, (mapcar #'car some-list) or (mapcar
#'slot-definition-name some-slots) in my code, it's unlikely that this
is going to change. However, when I say (remove-if-not #'some-property-p
some-list), my guess is that it's more likely that I will touch that
code again to modify the conditions, in the sense of refactoring my code
when I better understand what it's supposed to be doing. The LOOP macro
is more flexible in changing the code, while remove-if-not only allows
certain changes.

But that's probably just guesswork. ;)

mmcconn...@yahoo.com

unread,
Aug 3, 2006, 10:18:49 AM8/3/06
to

Tayssir John Gabbour wrote:
> I sometimes think remove-if-not would be used even more if named
> something like 'keep', or SICP's 'filter'. Because there's something
> double negative-ish about it.
>
> Tayssir

I remember once seeing subset as a synonym for remove-if-not, and
subset-not for remove-if. Was that Symbolics Lisp in the 1980s?

Joe Marshall

unread,
Aug 3, 2006, 1:44:42 PM8/3/06
to

Jonathon McKitrick wrote:
> It seems to me that popular opinion leans toward LOOP in favor of map
> and variants where either would apply

Allow me to be the token knee-jerk anti-loopist. I hate LOOP.

>, for the following reasons, to
> mention a few:
>
> 1. LOOP is more readable

I don't know what you mean by readable. It certainly sounds more like
english when you read it out loud from left to right, but I find it to
be less easy to predict what the resulting code will look like after it
is expanded.

> 2. LOOP is more efficient

Than MAP? Loop should be as efficient as the constructs it expands
into. There is no reason that MAP cannot be as efficient.

> 3. LOOP forms are more easily modified and expanded

I don't know how you define `ease of modification'. I've never found
mapping constructs that hard to modify.

> Are these the main reasons, or are there others? Any to the contrary?

My primary objection to LOOP is that it is extremely difficult to write
meta-level code that can manipulate loop expressions. A MAP expression
is just a function call, but LOOP requires a serious state-machine to
parse. You can macro-expand the LOOP away, but the resulting expansion
is almost as hard to understand as the original.

My second objection to LOOP is that it operates at a low level of
abstraction. One very frequent use of iteration is when you wish to
apply an operation to a collection of objects. You shouldn't have to
specify how the collection is traversed, and you certainly shouldn't
have to specify a serial traversal algorithm if it doesn't matter.
LOOP intertwines the operation you wish to perform with the minutiae of
traversal --- finding an initial element, stepping to the next element,
stopping when done. I don't care about these details. I don't care if
the program LOOPs, uses recursion, farms out the work to other
processors, or whatever, so long as it produces the answer I want.

Timofei Shatrov

unread,
Aug 3, 2006, 2:08:53 PM8/3/06
to
On 3 Aug 2006 06:17:40 -0700, "Tayssir John Gabbour"
<tayss...@yahoo.com> tried to confuse everyone with this message:

Being deprecated by ANSI standard doesn't help it either.

--
|Don't believe this - you're not worthless ,gr---------.ru
|It's us against millions and we can't take them all... | ue il |
|But we can take them on! | @ma |
| (A Wilhelm Scream - The Rip) |______________|

Thomas A. Russ

unread,
Aug 3, 2006, 2:37:12 PM8/3/06
to

Jonathon McKitrick wrote:
> It seems to me that popular opinion leans toward LOOP in favor of map
> and variants where either would apply, for the following reasons, to
> mention a few:
>
> 1. LOOP is more readable
> 2. LOOP is more efficient
> 3. LOOP forms are more easily modified and expanded
>
> Are these the main reasons, or are there others? Any to the contrary?

Contrary:

1. For the standard cases, MAPx is more concise.
2. The mapping functions can work with any kind of sequence without the
need to switch the syntax. Compare

(mapcar #'+ '(1 2 3) #(3 2 1))

(loop for i in '(1 2 3)
as j across #(3 2 1)
collect (+ i j))

3. The mapping functions make it easier to add additional arguments to
varible arity functions.
4. The general MAP function can return a sequence of any kind.


And for a mostly theoretical issue:

T1. MAPx can be implemented in parallel with non-side-effecting
functions. This is generally not done, however.

--
Thomas A. Russ, USC/Information Sciences Institute

Pascal Bourguignon

unread,
Aug 3, 2006, 3:13:03 PM8/3/06
to
t...@sevak.isi.edu (Thomas A. Russ) writes:

> Jonathon McKitrick wrote:
>> It seems to me that popular opinion leans toward LOOP in favor of map
>> and variants where either would apply, for the following reasons, to
>> mention a few:
>>
>> 1. LOOP is more readable
>> 2. LOOP is more efficient
>> 3. LOOP forms are more easily modified and expanded
>>
>> Are these the main reasons, or are there others? Any to the contrary?
>
> Contrary:
>
> 1. For the standard cases, MAPx is more concise.
> 2. The mapping functions can work with any kind of sequence without the
> need to switch the syntax. Compare
>
> (mapcar #'+ '(1 2 3) #(3 2 1))

You mean MAP (or MAP-INTO):

(MAP 'list (function +) '(1 2 3) #(3 2 1))


> (loop for i in '(1 2 3)
> as j across #(3 2 1)
> collect (+ i j))
>
> 3. The mapping functions make it easier to add additional arguments to
> varible arity functions.
> 4. The general MAP function can return a sequence of any kind.
>
>
> And for a mostly theoretical issue:
>
> T1. MAPx can be implemented in parallel with non-side-effecting
> functions. This is generally not done, however.
>
> --
> Thomas A. Russ, USC/Information Sciences Institute

--
__Pascal Bourguignon__ http://www.informatimago.com/
Our enemies are innovative and resourceful, and so are we. They never
stop thinking about new ways to harm our country and our people, and
neither do we. -- Georges W. Bush

Matthew D Swank

unread,
Aug 3, 2006, 4:44:07 PM8/3/06
to
On Wed, 02 Aug 2006 17:06:34 -0700, nallen05 wrote:

> jkf's "Lisp Coding Standards v1.0" [1] says it well:
>
> "Use do, dotimes and dolist for iteration in place of the extended loop
> macro (the one using the keywords). The structure of the code inside
> a loop is not apparent. Thus a function with loop in it is opaque
> until you've read carefully through all the keywords used in the
> expression."

I really loathed 'do' until I realized it looked like a "'let' in motion".
Though, it looks so much like functional code, I would sometimes forget
that each iteration does not generate a fresh set of bindings for the loop
variables. This, of course, can cause problems when you close over one of
them.

Matt

--
"You do not really understand something unless you can
explain it to your grandmother." — Albert Einstein.

Ari Krupnik

unread,
Aug 3, 2006, 5:20:20 PM8/3/06
to
"Joe Marshall" <eval....@gmail.com> writes:

> My second objection to LOOP is that it operates at a low level of
> abstraction. One very frequent use of iteration is when you wish to
> apply an operation to a collection of objects. You shouldn't have to
> specify how the collection is traversed, and you certainly shouldn't
> have to specify a serial traversal algorithm if it doesn't matter.

That last would seem to be an argument against mapcar, no?

Ari.


--
Elections only count as free and trials as fair if you can lose money
betting on the outcome.

mac

unread,
Aug 3, 2006, 5:08:22 PM8/3/06
to

To tell you the truth, it really doesn't matter, use whatever construct
that make your code as clear as possible in the context.

I found that do is hard to read. dolist and dotimes are mostly good for
simple iteration. Like kenny mentioned, unless I have a named function
to pass to map-xxx, I'd rather use loop instead of (map-xxx
(lambda)...) because the code will be less verbose.

Actually iterate is better than loop technically (you can use arbitrary
lisp code for conditional branching, whereas with loop you can only use
the built-in keyword, and lots of cool constructs like generators, etc
etc)

For this reason I procrastined to learn the loop syntax initially after
I found iterate.

Iterate's documentation is excellent, it can do everything that loop
can do and more, and I learn all the features after reading the manual.
Much shorter time it took me to learn loop.

But eventually I still need to master the loop sytnax, because
everybody else is using it and in reality very few people use iterate.
It's very counter productive if I have to stop and think about what it
does whenever I see a loop construct.

Now I prefer to use loop whenever possible, and only use iterate after
I tried really hard and cannot find a elegant solution with loop.

It's sad, it's the same reason why lisp is not popular (and will never
be) even it's the best high level programming language ever invented.

franks

unread,
Aug 3, 2006, 5:28:59 PM8/3/06
to

Why does nearly no one use iterate ? I believe it is, compared to loop,
much more readable, concise and powerfull and extendable, and it is
apparently rarely used. Is there a reason for that ?
Frank

Pascal Costanza

unread,
Aug 3, 2006, 5:51:31 PM8/3/06
to
Matthew D Swank wrote:
> On Wed, 02 Aug 2006 17:06:34 -0700, nallen05 wrote:
>
>> jkf's "Lisp Coding Standards v1.0" [1] says it well:
>>
>> "Use do, dotimes and dolist for iteration in place of the extended loop
>> macro (the one using the keywords). The structure of the code inside
>> a loop is not apparent. Thus a function with loop in it is opaque
>> until you've read carefully through all the keywords used in the
>> expression."
>
> I really loathed 'do' until I realized it looked like a "'let' in motion".
> Though, it looks so much like functional code, I would sometimes forget
> that each iteration does not generate a fresh set of bindings for the loop
> variables. This, of course, can cause problems when you close over one of
> them.

...but is easy to resolve:

(let (result)
(do ((some-var ...))
(...)
(let ((some-var some-var)) ; create new binding for current value
(push (lambda (...) ... some-var ...) result)))
(nreverse result))

Pascal Costanza

unread,
Aug 3, 2006, 6:03:53 PM8/3/06
to
franks wrote:
> Joe Marshall wrote:

>> My primary objection to LOOP is that it is extremely difficult to write
>> meta-level code that can manipulate loop expressions. A MAP expression
>> is just a function call, but LOOP requires a serious state-machine to
>> parse. You can macro-expand the LOOP away, but the resulting expansion
>> is almost as hard to understand as the original.
>>
>> My second objection to LOOP is that it operates at a low level of
>> abstraction. One very frequent use of iteration is when you wish to
>> apply an operation to a collection of objects. You shouldn't have to
>> specify how the collection is traversed, and you certainly shouldn't
>> have to specify a serial traversal algorithm if it doesn't matter.
>> LOOP intertwines the operation you wish to perform with the minutiae of
>> traversal --- finding an initial element, stepping to the next element,
>> stopping when done. I don't care about these details. I don't care if
>> the program LOOPs, uses recursion, farms out the work to other
>> processors, or whatever, so long as it produces the answer I want.
>
> Why does nearly no one use iterate ? I believe it is, compared to loop,
> much more readable, concise and powerfull and extendable, and it is
> apparently rarely used. Is there a reason for that ?

iterate doesn't address Joe's objections. It's still an iteration
construct and not a declarative one.

List comprehensions, or similar declarative abstractions, would address
them.

Indeed that's how I try to use LOOP. When I say this:

(loop for elem in list
when (some-predicate elem)
collect elem)

...I try not to understand this as an iteration, but as a declarative
expression of the result I want. More often than not, this works
sufficiently well, but Joe is right that LOOP is at least sometimes not
optimal in this regard. However, IMHO, as a poor man's list
comprehension facility it's mostly good enough.

The prime advantage of LOOP is that it's part of ANSI Common Lisp and so
available by default everywhere.

Nathan Baum

unread,
Aug 3, 2006, 6:41:12 PM8/3/06
to
On Thu, 3 Aug 2006, Joe Marshall wrote:
>
> Jonathon McKitrick wrote:
>> It seems to me that popular opinion leans toward LOOP in favor of map
>> and variants where either would apply
>
> Allow me to be the token knee-jerk anti-loopist. I hate LOOP.
>
>> , for the following reasons, to
>> mention a few:
>>
>> 1. LOOP is more readable
>
> I don't know what you mean by readable. It certainly sounds more like
> english when you read it out loud from left to right, but I find it to
> be less easy to predict what the resulting code will look like after it
> is expanded.

Why is that important?

>> 2. LOOP is more efficient
>
> Than MAP? Loop should be as efficient as the constructs it expands
> into. There is no reason that MAP cannot be as efficient.
>
>> 3. LOOP forms are more easily modified and expanded
>
> I don't know how you define `ease of modification'. I've never found
> mapping constructs that hard to modify.

Suppose you have

(loop for x in (get-list)
do (format t "~A~%" x))

and then it turns out you need to print a numeric index. You can do

(loop for x in (get-list)
for i from 0
do (format t "~A - ~A~%" i x))

If you start with

(mapc (lambda (x) (format t "~A~%" x)) (get-list))

it seems (to me) that it'd be harder to modify it as needed,

(let ((list (get-list)))
(mapc (lambda (i x) (format t "~A - ~A" i x))
(range 0 (length list))
list))

(I'm assuming the toolkit includes a RANGE utility, or something similar.)

Then suppose you later need the loop/map to collect some of the values
under certain conditions. You might have

(loop for x in (get-list)
for i from 0
do (format t "~A - ~A~%" i x)
if (test x)
collect (foo x))

compared to

(let ((list (get-list)))
(mapcan (lambda (i x)
(format t "~A - ~A" i x)
(if (test x)
(list (foo x))
nil))
(range 0 (length list))
list))

Not only did I not have to change as much code to make the LOOP do what I
wanted, it's also obvious (to me) that the LOOP does what I intend, whilst
I'd have to spend a little extra time testing the MAPCAN to make sure it's
really doing what I think it would.

>> Are these the main reasons, or are there others? Any to the contrary?
>
> My primary objection to LOOP is that it is extremely difficult to write
> meta-level code that can manipulate loop expressions. A MAP expression
> is just a function call, but LOOP requires a serious state-machine to
> parse. You can macro-expand the LOOP away, but the resulting expansion
> is almost as hard to understand as the original.

The solution to this seems to be not to use LOOP in code which is
destined for transformation.

> My second objection to LOOP is that it operates at a low level of
> abstraction. One very frequent use of iteration is when you wish to
> apply an operation to a collection of objects. You shouldn't have to
> specify how the collection is traversed, and you certainly shouldn't
> have to specify a serial traversal algorithm if it doesn't matter.
> LOOP intertwines the operation you wish to perform with the minutiae of
> traversal --- finding an initial element, stepping to the next element,
> stopping when done.

I'm pretty sure it doesn't.

(loop for x in list do (format t "~A: ~A~%" x (foo x)))

doesn't seem any more concerned with the mechanics of the traversal than

(mapc (lambda (x) (format t "~A: ~A~%" x (foo x))) list)

Certainly it's *possible* to write a LOOP which manually deals with CARs
and CDRs. But you don't *have* to, and unless it matters, I don't.

Stefan Mandl

unread,
Aug 3, 2006, 7:30:43 PM8/3/06
to
> - More often than not, the different variables actually iterate over
> different kinds of values. Recently, I needed the following costruct
> quite often:
>
> (loop for x in some-list
> for i from 0
> collect `(,x ,i))
>

Hey Pascal, how about

(reverse (maplist #'(lambda (l) `(,(first l) ,(- (length l) 1))) (reverse some-list)))

.. but .. hmm no, that's way to inefficient and plain ugly .. your are right ;)

Jonathon McKitrick

unread,
Aug 3, 2006, 10:33:13 PM8/3/06
to

Matthew D Swank wrote:
> I really loathed 'do' until I realized it looked like a "'let' in motion".

'It is through will alone I LET my mind in motion....'

Rob Warnock

unread,
Aug 4, 2006, 12:09:10 AM8/4/06
to
Matthew D Swank <akopa-is-very-much-...@c.net> wrote:
+---------------

| I really loathed 'do' until I realized it looked like a "'let' in motion".
| Though, it looks so much like functional code, I would sometimes forget
| that each iteration does not generate a fresh set of bindings for the
| loop variables.
+---------------

This is one of the "gotchas" I occasionally bumped into while I was
in the process of moving over from Scheme to CL several years ago.
The Scheme spec requires that each iteration generate a fresh set
of bindings for the variables, while the CLHS requires that the
variables be bound but once and then subsequently assigned-to
["in parallel, as if by PSETQ" for DO, and "sequentially, as if
by SETQ" for DO*].


-Rob

-----
Rob Warnock <rp...@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607

Rob Warnock

unread,
Aug 4, 2006, 12:17:36 AM8/4/06
to
Timofei Shatrov <gr...@mail.ru> wrote:
+---------------

| <tayss...@yahoo.com> tried to confuse everyone with this message:
| >I sometimes think remove-if-not would be used even more if named
| >something like 'keep', or SICP's 'filter'. Because there's something
| >double negative-ish about it.
|
| Being deprecated by ANSI standard doesn't help it either.
+---------------

But don't forget that all of the "deprecated" features in
CLHS are still *required* to be present in an implementation
that purports to be a "Common Lisp".

1.8 Deprecated Language Features

Deprecated language features are not expected to appear
in future Common Lisp tandards, but are required to
be implemented for conformance with this standard; see
Section 1.5.1.1 (Required Language Features).

Rob Warnock

unread,
Aug 4, 2006, 12:52:49 AM8/4/06
to
Pascal Costanza <p...@p-cos.net> wrote:
+---------------

| List comprehensions, or similar declarative abstractions, would address
| them. Indeed that's how I try to use LOOP. When I say this:
| (loop for elem in list
| when (some-predicate elem)
| collect elem)
| ...I try not to understand this as an iteration, but as a declarative
| expression of the result I want.
+---------------

And to my taste, that's *much* cleaner looking and
more comprehensible [pardon the pun!] six months later
than anything I can think of writing with MAPxxx.

The combination of LOOP...WHEN...COLLECT work particularly
well together, especially when there are multiple WHEN...COLLECT
sub-expressions. Here's an admittedly-ugly [but useful] piece
of code. Would a MAPxxx version be more readable?

;;; Spray bits out for easy reading of hardware registers
(defun decode-bits (n)
(let ((mflag (minusp n)))
(when mflag
(setf n (lognot n)))
(loop for i downfrom (integer-length n) to 0
when mflag
collect (if (zerop n) 'all-ones 'all-ones-except)
and do (setf mflag nil)
when (logbitp i n)
collect i)))

Usage:

> (decode-bits 16542)

(14 7 4 3 2 1)
> (decode-bits -16542)

(ALL-ONES-EXCEPT 14 7 4 3 2 0)
> (decode-bits -1)

(ALL-ONES)

zell...@gmail.com

unread,
Aug 4, 2006, 2:25:14 AM8/4/06
to
Jonathon McKitrick wrote:
> It seems to me that popular opinion leans toward LOOP in favor of map
> and variants where either would apply, for the following reasons, to
> mention a few:

I would like to add a third item to this poll: when, if ever, do you
think series (or some similar approach) could be preferable to those
above. It is (if I understand correctly) another iteration mechanism
that almost got to a standard a time ago, it looks quite elegant, but I
dont think I have ever seen it used in recent public code (and,
honestly, when I tried to use it, it seemed to be too compilcated for
casual use)

Tomas

Lars Brinkhoff

unread,
Aug 4, 2006, 3:01:18 AM8/4/06
to
rp...@rpw3.org (Rob Warnock) writes:
> The combination of LOOP...WHEN...COLLECT work particularly well
> together, especially when there are multiple WHEN...COLLECT
> sub-expressions. Here's an admittedly-ugly [but useful] piece of
> code.
>
> (defun decode-bits (n)
> (let ((mflag (minusp n)))
> (when mflag
> (setf n (lognot n)))
> (loop for i downfrom (integer-length n) to 0
> when mflag
> collect (if (zerop n) 'all-ones 'all-ones-except)
> and do (setf mflag nil)
> when (logbitp i n)
> collect i)))

I think I would like to rearrange the logic slightly:

(defun decode-bits (n)
(cond
((eql n -1) '(all-ones))
((minusp n) (cons 'all-ones-except (decode-bits (lognot n))))
(t


(loop for i downfrom (integer-length n) to 0

when (logbitp i n)
collect i))))

> Would a MAPxxx version be more readable?

Starting from this later version, and assuming some kind of MAP-BITS
function, I don't think it would too bad. But in this case, a mapping
operation may not be suitable. You don't want to map the bits in one
integer to some other bits in a resulting integer.

Rob Warnock

unread,
Aug 4, 2006, 3:42:46 AM8/4/06
to
Lars Brinkhoff <lars...@nocrew.org> wrote:
+---------------

| I think I would like to rearrange the logic slightly:
| (defun decode-bits (n)
| (cond
| ((eql n -1) '(all-ones))
| ((minusp n) (cons 'all-ones-except (decode-bits (lognot n))))
| (t
| (loop for i downfrom (integer-length n) to 0
| when (logbitp i n)
| collect i))))
+---------------

Yeah, that is much cleaner, thanks!!

+---------------


| > Would a MAPxxx version be more readable?
|
| Starting from this later version, and assuming some kind of MAP-BITS
| function, I don't think it would too bad.

+---------------

Well, the guts of it is still the LOOP...WHEN...COLLECT idiom,
and that's going to need a hairy MAPCAN or something to get
equivalent behavior. Not to mention that COLLECT is generally much
more efficient that the (REVERSE (DOxxx ... (WHEN ... (PUSH ...))))
idiom.

Tayssir John Gabbour

unread,
Aug 4, 2006, 5:07:20 AM8/4/06
to
Rob Warnock wrote:

> Timofei Shatrov <gr...@mail.ru> wrote:
> | <tayss...@yahoo.com> tried to confuse everyone with this message:
> | >I sometimes think remove-if-not would be used even more if named
> | >something like 'keep', or SICP's 'filter'. Because there's something
> | >double negative-ish about it.
> |
> | Being deprecated by ANSI standard doesn't help it either.
>
> But don't forget that all of the "deprecated" features in
> CLHS are still *required* to be present in an implementation
> that purports to be a "Common Lisp".

My understanding is that the deprecation was informally deprecated. ;)

Kent Pitman wrote:

<sfwwv0j...@shell01.TheWorld.com>
> I think it's generally accepted in the community that we made a mistake
> deprecating those.
>
> You should use :test (complement test) rather than :test-not test.
> But for the -if-not functions, just use them and ignore the deprecation.
http://groups.google.com/group/comp.lang.lisp/msg/60b5bda8223abaf2


IIRC, Peter Seibel's PCL guesstimated that remove-if-not is probably
used more (or at least is more useful) than remove.


Tayssir

Jonathon McKitrick

unread,
Aug 4, 2006, 8:22:46 AM8/4/06
to
When is it really useful to iterate over a list, then the cdr of the
list again, the the cddr... etc?

I just can't come up with a non-contrived example.

Frank Buss

unread,
Aug 4, 2006, 8:54:27 AM8/4/06
to
Jonathon McKitrick wrote:

a quick hack:

(defun all-combinations (list)
(let ((combinations '()))
(maplist (lambda (cdr)
(let ((car (car cdr)))
(mapcar (lambda (element)
(push (list car element) combinations))
cdr)))
list)
combinations))

CL-USER > (all-combinations '(1 2 3 4))
((4 4) (3 4) (3 3) (2 4) (2 3) (2 2) (1 4) (1 3) (1 2) (1 1))

--
Frank Buss, f...@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de

Timofei Shatrov

unread,
Aug 4, 2006, 9:35:42 AM8/4/06
to
On 4 Aug 2006 05:22:46 -0700, "Jonathon McKitrick"
<j_mck...@bigfoot.com> tried to confuse everyone with this message:

>When is it really useful to iterate over a list, then the cdr of the
>list again, the the cddr... etc?
>
>I just can't come up with a non-contrived example.
>

(loop for x on list do ...)

Lars Brinkhoff

unread,
Aug 4, 2006, 9:46:15 AM8/4/06
to
rp...@rpw3.org (Rob Warnock) writes:

> Lars Brinkhoff <lars...@nocrew.org> wrote:
> > (loop for i downfrom (integer-length n) to 0
> > when (logbitp i n)
> > collect i)
> > > Would a MAPxxx version be more readable?
> > Starting from this later version, and assuming some kind of MAP-BITS
> > function, I don't think it would too bad.
> Well, the guts of it is still the LOOP...WHEN...COLLECT idiom,
> and that's going to need a hairy MAPCAN or something to get
> equivalent behavior.

I said "assuming some kind of MAP-BITS", which would let me write

(let ((bits nil))
(map-bits/index (lambda (bit i)
(when bit
(push i bits)))
n)
bits)

While I wouldn't necessarily say this is "more readable", I still
don't think it's "too bad".

If MAP-BITS/INDEX is too much of a stretch (why, it should be in every
bit-manipulating programmer's toolbox!), you could imagine a more
general version operating on an integer exploded into a sequence of
bits. (For now, we're more interested in readability than efficiency,
right?)

(reverse
(filter/index (lambda (bit i)
(if bit
i ;Collect this.
(values))) ;Nothing to collect.
(integer-bit-vector n)))

I'm still not advocating this style of programming, just trying to
provide alternatives to hairy old MAPCAN idioms etc.

> Not to mention that COLLECT is generally much more efficient that
> the (REVERSE (DOxxx ... (WHEN ... (PUSH ...)))) idiom.

Agreed. When not using LOOP, I prefer to use some kind of
WITH-COLLECTOR macro.

Timofei Shatrov

unread,
Aug 4, 2006, 1:22:10 PM8/4/06
to
On Fri, 04 Aug 2006 13:35:42 GMT, gr...@mail.ru (Timofei Shatrov) tried

to confuse everyone with this message:

>On 4 Aug 2006 05:22:46 -0700, "Jonathon McKitrick"
><j_mck...@bigfoot.com> tried to confuse everyone with this message:
>
>>When is it really useful to iterate over a list, then the cdr of the
>>list again, the the cddr... etc?
>>
>>I just can't come up with a non-contrived example.
>>
>
>(loop for x on list do ...)
>

Oops - I was thinking that this is the continuation of MAP* vs LOOP
debate... Anyway, I used (loop for ... on ...) several times, but this
loop either exited early (allowing to get the tail quickly) or I used
"by #'cddr" to get at two consecutive elements. Both of these uses are
impractical with MAPLIST.

Joe Marshall

unread,
Aug 4, 2006, 2:31:28 PM8/4/06
to

Ari Krupnik wrote:
> "Joe Marshall" <eval....@gmail.com> writes:
>
> > My second objection to LOOP is that it operates at a low level of
> > abstraction. One very frequent use of iteration is when you wish to
> > apply an operation to a collection of objects. You shouldn't have to
> > specify how the collection is traversed, and you certainly shouldn't
> > have to specify a serial traversal algorithm if it doesn't matter.
>
> That last would seem to be an argument against mapcar, no?

It could be, if I relied on mapcar using left-to-right traversal. I
try to avoid depending on that.

Joe Marshall

unread,
Aug 4, 2006, 2:41:00 PM8/4/06
to

Nathan Baum wrote:
> On Thu, 3 Aug 2006, Joe Marshall wrote:
> >
> > I don't know what you mean by readable. It certainly sounds more like
> > english when you read it out loud from left to right, but I find it to
> > be less easy to predict what the resulting code will look like after it
> > is expanded.
>
> Why is that important?

I understand code by considering alternatives to what I write. It
isn't obvious to me what parts of a loop end up where in the result and
what parts are nested in what other parts.

I suppose in these cases LOOP is easier to modify.

> >> Are these the main reasons, or are there others? Any to the contrary?
> >
> > My primary objection to LOOP is that it is extremely difficult to write
> > meta-level code that can manipulate loop expressions. A MAP expression
> > is just a function call, but LOOP requires a serious state-machine to
> > parse. You can macro-expand the LOOP away, but the resulting expansion
> > is almost as hard to understand as the original.
>
> The solution to this seems to be not to use LOOP in code which is
> destined for transformation.

If I don't use LOOP at all, this is easy.

Joe Marshall

unread,
Aug 4, 2006, 3:09:05 PM8/4/06
to

zell...@gmail.com wrote:
>
> I would like to add a third item to this poll: when, if ever, do you
> think series (or some similar approach) could be preferable to those
> above. It is (if I understand correctly) another iteration mechanism
> that almost got to a standard a time ago, it looks quite elegant, but I
> dont think I have ever seen it used in recent public code (and,
> honestly, when I tried to use it, it seemed to be too compilcated for
> casual use)

I've used series. In the cases where it works, it works well, but in
other cases it can be really nasty. For example, I have some code that
manipulates strings in various formats. One format it handles is
simple-arrays of (unsigned-byte 8) which contain the code-points of a
string encoded in UTF-8. When I want to print one of these, I use this
code:

(collect-stream
stream
(#m code-char
(ucs-4->ucs-2
(utf-8->ucs-4
(scan 'simple-vector-8b code-unit-vector))))
#'write-char)

The underlying lisp uses UCS-2 (16-bit old-style unicode) and I'm
ignoring surrogates.

As you can see, this code is *really* easy to understand: You scan
across the code units, transcode them from utf-8 to ucs-4, transcode
again to ucs-2, convert to characters, and write them to the stream. I
could have written a utf-8->ucs-2 converter, but it didn't seem worth
it.

There is a catch. The code for utf-8->ucs-4 is *horrendous*. The
series code likes to work in `lock step' mode: each input quantum
should produce exactly one output quantum. When things are in lock
step, the series code can unroll all the mapping into a single loop.
Unfortunately, utf8 encoding uses from one to six bytes to encode a
32-bit value, so we violate the lock step condition early on in the
process.

Fortunately, the series code can handle a *little* bit of asynchronous
code provided you meet some complicated restrictions. With a bit of
trickery, you can get the utf8 decoding to be close enough to lock step
that rest of the code will optimize.

I really like how series makes some code extremely clean, but it comes
at the cost of making some code even more extremely messy.

nall...@gmail.com

unread,
Aug 4, 2006, 3:51:38 PM8/4/06
to

I don't know about MAPLIST, but I've used MAPL to iterate over the
elements of a list when I needed to pass what the remaining elements of
the list are to the operation on the elements...

Also wouldn't you need MAPL to impliment something like MEMBER?

Nick

Ken Tilton

unread,
Aug 4, 2006, 6:10:04 PM8/4/06
to

Joe Marshall wrote:
> Jonathon McKitrick wrote:
>
>>It seems to me that popular opinion leans toward LOOP in favor of map

>>and variants where either would apply
>
>
> Allow me to be the token knee-jerk anti-loopist. I hate LOOP.
>
>

>>, for the following reasons, to
>>mention a few:
>>

>>1. LOOP is more readable
>
>

> I don't know what you mean by readable.

No code is readable. But LOOP is more writeable. Anyway...

>>2. LOOP is more efficient
>
>
> Than MAP? Loop should be as efficient as the constructs it expands
> into. There is no reason that MAP cannot be as efficient.

Well, I think the point is that LOOP automates things like collecting
and does so efficiently saving me the effort.


>
> My primary objection to LOOP is that it is extremely difficult to write
> meta-level code that can manipulate loop expressions.

That's a good one. I myself have never reached that particular
meta-level, but then I am just a simple application programmer.


> My second objection to LOOP is that it operates at a low level of
> abstraction. One very frequent use of iteration is when you wish to
> apply an operation to a collection of objects. You shouldn't have to
> specify how the collection is traversed,

You mean: (loop for item in list...)? Hmmmm.

But now that you mention it, of course the brilliant thing about loop is
that you can do destructuring: (loop (for (thing1 thing2) in list...

And i can use WITH for any LETs I would normally need. And I must say my
LOOPS tend to be either very simple and obvious (and then I do not have
to type l-a-m-b-d-a!) or very hairy in which case in one form (however
un-lispy and un-meta-parseable) I can get a whole lotta stuff written
that would not appear so self-contained (which maybe gets to the
readability/maintainability points).

In the end it comes back to my first point: you cannot compare MAP and
LOOP, when one is using the full power of LOOP and its DSL quality is
apparent (at which point the equivalent loop-less lisp is to a degree
like writing assembler instead of an HLL.

kt

--
Cells: http://common-lisp.net/project/cells/

"I'll say I'm losing my grip, and it feels terrific."
-- Smiling husband to scowling wife, New Yorker cartoon

Ken Tilton

unread,
Aug 5, 2006, 12:29:21 AM8/5/06
to

mac wrote:

> It's sad, it's the same reason ...

worse is better...

>...why lisp is not popular (and will never
> be)

If you have a crystal ball so reliable that you will bet the ranch
against the best language catching on in a world still in turmoil and
moving ever closer to Lisp's features, get the fuck off c.l.l and into
the penny markets.

hth, kt

Pascal Costanza

unread,
Aug 5, 2006, 2:46:20 AM8/5/06
to
Ken Tilton wrote:

>
>
> Joe Marshall wrote:
>>
>> My primary objection to LOOP is that it is extremely difficult to write
>> meta-level code that can manipulate loop expressions.
>
> That's a good one. I myself have never reached that particular
> meta-level, but then I am just a simple application programmer.

You don't write macros?!?

Jonathon McKitrick

unread,
Aug 5, 2006, 3:05:50 AM8/5/06
to
Here's a real-world problem I'm working on:

I have one target array and 5 reference arrays, all with just a few
dozen elements and all the same size/type. I want to compare the
target array to each of the reference arrays simply by summing the
absolute value of the difference between target array element x and
reference array element x, for all elements.

Originally, all I returned was the index of the array most closely
matching the target.
Note: 'rpt' is an object with a 'target-array' slot.

(defun fit-profiles (rpt)
(let (total-deltas)
(dotimes (i 5)
(let ((profile-id (search-profiles (format nil "profile~A" (1+
i)))))
(push
(reduce #'+ (mapcar #'(lambda (a b) (abs (- a b))) (target-array rpt)
(get-reference-array profile-id)))
total-deltas)))
(1+ (position (apply #'min total-deltas) (nreverse
total-deltas))))))

In the next round, I am not only interested in the closest match, but
the next closest match as well. So now I will return not only the
closest match, but total-deltas also.

I started writing this with LOOP, but the nature of calculating the
deltas seemed fit so well with mapcar, why bother? But maybe I'm
overlooking a better way, especially since returning the list of deltas
results in an ugly (setf total-deltas (nreverse total-deltas)) which
LOOP could avoid with COLLECT. I'm also allowing for the possibility
there is a more elegant solution using neither LOOP nor MAPCAR that I
haven't found yet either.

Message has been deleted

lispolos

unread,
Aug 5, 2006, 3:28:52 AM8/5/06
to

Jonathon McKitrick wrote:
> Are these the main reasons, or are there others? Any to the contrary?

Loop is only a language addition anybody is free to like or dislike, it
is certainly no distinctive "feature" of Lisp.

I love loop, in exactly one situation: a simple forever loop with no
loop clauses.

For all other situations I prefer a way where I can read exactly how it
will be done.

(BTW, it's more or less the same with regular expressions: in Lisp you
can do surprisingly often without them, beeing able to also see exactly
how it is done, where in many other languages it would be very
difficult to code without, and how it is done is more or less hidden by
the regular expression...)

Paul

Ken Tilton

unread,
Aug 5, 2006, 5:09:48 AM8/5/06
to

Pascal Costanza wrote:
> Ken Tilton wrote:
>
>>
>>
>> Joe Marshall wrote:
>>
>>>
>>> My primary objection to LOOP is that it is extremely difficult to write
>>> meta-level code that can manipulate loop expressions.
>>
>>
>> That's a good one. I myself have never reached that particular
>> meta-level, but then I am just a simple application programmer.
>
>
> You don't write macros?!?

One of us did not understand Mr. Marshall.

:)

ken

Jonathon McKitrick

unread,
Aug 5, 2006, 1:03:01 PM8/5/06
to

lispolos wrote:
> (BTW, it's more or less the same with regular expressions: in Lisp you
> can do surprisingly often without them, beeing able to also see exactly
> how it is done, where in many other languages it would be very
> difficult to code without, and how it is done is more or less hidden by
> the regular expression...)

Any examples of this you can offer?

Bill Atkins

unread,
Aug 5, 2006, 1:14:19 PM8/5/06
to
lispolos wrote:
> Jonathon McKitrick wrote:
> > Are these the main reasons, or are there others? Any to the contrary?
>
> Loop is only a language addition anybody is free to like or dislike, it
> is certainly no distinctive "feature" of Lisp.

Sure it is. What other language has anything like LOOP? And what
other language would let the developer add LOOP if it didn't already
exist?

Friedrich Dominicus

unread,
Aug 5, 2006, 1:27:24 PM8/5/06
to
"Bill Atkins" <batk...@gmail.com> writes:

Tcl/Tk
and IO come to my mind immediatly.

I guess it could work in Ocaml also

Regards
Friedrich


--
Please remove just-for-news- to reply via e-mail.

Steven E. Harris

unread,
Aug 5, 2006, 3:30:21 PM8/5/06
to
Joe Marshall <eval....@gmail.com> writes:

> With a bit of trickery, you can get the utf8 decoding to be close
> enough to lock step that rest of the code will optimize.

Joe had been kind enough to explain the gory details in the thread
"Generators in Lisp" from June 2004.ą


Footnotes:
ą http://groups.google.com/group/comp.lang.lisp/browse_frm/thread/1b8d5d7c129aa259/a38d231b39f48e34?#a38d231b39f48e34

--
Steven E. Harris

Nathan Baum

unread,
Aug 5, 2006, 3:55:20 PM8/5/06
to

That's exactly *why* I use regular expressions. I don't care about *how*
it's done, I just want to tell the program *what* should be done, and it
makes it so. Apart from making things easier (IMO), it also means that
improvements in the regular expression engine are automatically passed on
to my code. Even though the *how* might change in the engine, the *what*
I've specified in my code remains the same.

> Paul

Larry Elmore

unread,
Aug 5, 2006, 4:59:02 PM8/5/06
to
Friedrich Dominicus wrote:
> "Bill Atkins" <batk...@gmail.com> writes:
>
>> lispolos wrote:
>>> Jonathon McKitrick wrote:
>>>> Are these the main reasons, or are there others? Any to the contrary?
>>> Loop is only a language addition anybody is free to like or dislike, it
>>> is certainly no distinctive "feature" of Lisp.
>> Sure it is. What other language has anything like LOOP? And what
>> other language would let the developer add LOOP if it didn't already
>> exist?
> Tcl/Tk
> and IO come to my mind immediatly.
>
> I guess it could work in Ocaml also

Forth, certainly.

--Larry

Christopher Browne

unread,
Aug 5, 2006, 10:31:20 PM8/5/06
to
"Jonathon McKitrick" <j_mck...@bigfoot.com> wrote:
> Matthew D Swank wrote:
>> I really loathed 'do' until I realized it looked like a "'let' in motion".
>
> 'It is through will alone I LET my mind in motion....'

But which juice is it by which thoughts acquire speed? Perhaps that
from the beans of coffee???
--
"cbbrowne","@","gmail.com"
http://linuxdatabases.info/info/lisp.html
"Whenever you find that you are on the side of the majority, it is
time to reform." -- Mark Twain

Rob Warnock

unread,
Aug 5, 2006, 11:07:28 PM8/5/06
to
Jonathon McKitrick <j_mck...@bigfoot.com> wrote:
+---------------
+---------------

The following hack [with some names obfuscated] parses ".objd" files
[output from "objdump"] to collect a map of places in the target
code being debugged where the function "foo_trace()" was called.
[The function "foo_trace()" sticks its return address into a trace
buffer along with its other args, which is why this is useful.]

(defun load-trace-map (&key (file "home:build/test/foo/foo.objd")
(verbose nil))
(with-open-file (s file)
(setf *trace-map* (make-hash-table)) ; clear out old stuff
(loop with labels = 0
for line = (read-line s nil nil)
while line
when (and (> (length line) 10)
(not (mismatch line "0002" :end1 4))
(mismatch "foo_trace" line :start2 10 :end2 22)
(eql 0 (mismatch "<foo_trace>" line :from-end t)))
do (let* ((addr (parse-integer line :start 4 :end 8 :radix 16))
(end (position #\> line))
(label (subseq line 10 end)))
(when verbose
(format t "~(0x~4,'0x~) ~a~%" addr label))
(incf labels)
(setf (gethash addr *trace-map*) label))
finally (format t "~d labels extracted~%" labels)))
(values))

That is, given ".objd" lines like these:

...
000217d4 <gorp+0x34> e1a01002 mov r1, r2
000217d8 <gorp+0x38> ebfffbc0 bl 000206e0 <foo_trace>
000217dc <gorp+0x3c> e5941000 ldr r1, [r4]
...

it will do a (SETF (GETHASH #x17d8 *TRACE-MAP*) "gorp+0x38").
So when the buffer is printed out, whenever the return address
#x17dc is seen in the trace buffer [which only stores the 16 LSBs],
the trace entry will be annotated with "gorp+0x38".

Novus

unread,
Aug 6, 2006, 12:41:00 PM8/6/06
to
On 2006-08-02 19:17:40 -0400, "Jonathon McKitrick"
<j_mck...@bigfoot.com> said:

> It seems to me that popular opinion leans toward LOOP in favor of map

> and variants where either would apply, for the following reasons, to


> mention a few:
>
> 1. LOOP is more readable

> 2. LOOP is more efficient

> 3. LOOP forms are more easily modified and expanded


>
> Are these the main reasons, or are there others? Any to the contrary?

I prefer ITERATE over LOOP for the same reasons you list above and because
ITERATE forms actually look like lisp code.

Novus

Message has been deleted

Nathan Baum

unread,
Aug 6, 2006, 4:34:11 PM8/6/06
to
On Sun, 6 Aug 2006, lispolos wrote:

> Jonathon McKitrick wrote:
>> Any examples of this you can offer?
>

> What I don't like in regular expressions is the fact that they may
> prevent you from discovering some more basic and simple pattern behind
> something (why should I prefer an expression like "[A-Za-z]" to a
> simple 'alpha-char-p' ?).

It's shorter?

It's easier to expand to include other characters?

It's easier to combine with other pattern-matching primitives?

The regular expression compiler deals with backtracking for you?

The regular expression compiler can apply optimisations which would be
tedious to apply by hand?

It matches the characters A-Z and a-z rather than whatever characters
might happen to pass alpha-char-p in your particular locale? (Important if
your app needs to comply with a protocol with firm ideas about what the
alphabet should be. If you want locale-specific test, use [[:alpha:]].
(Still shorter than alpha-char-p.))

Compare

(let-regexp (name value) header-line
#/^([^:])+:\ *(.*)$/x
(if name
(print `(,name ,value))
(print "; Not a header")))

with

(let ((cpos (position #\: header-line))
(name (if cpos (subseq string 0 cpos)))
(value (if cpos (subseq string
(position #'\Space header-line
:test-not #'eq
:start (1+ cpos))))))
(if name
(print `(,name ,value))
(print "; Not a header")))

> I simply don't like it when something is hidden behind an unnecessary
> convenience pseudo pattern -- this way I will never be able to discover
> the maybe much simpler, more original pattern behind something.

Then I guess you shouldn't be using Lisp: it hides things behind
simplified abstractions All The Time.

> IMO the above can happen with both LOOP and regular expressions (not in
> very simple cases, though).
>
> Paul

Message has been deleted

WJ

unread,
Feb 24, 2011, 5:14:06 PM2/24/11
to
Pascal Costanza wrote:

> Jonathon McKitrick wrote:
> > It seems to me that popular opinion leans toward LOOP in favor of
> > map and variants where either would apply, for the following
> > reasons, to mention a few:
> >
> > 1. LOOP is more readable
> > 2. LOOP is more efficient
> > 3. LOOP forms are more easily modified and expanded
> >
> > Are these the main reasons, or are there others? Any to the
> > contrary?
>

> mapcar and mapc are pretty useful when the function you want to map
> is already defined (or needs to be defined) anyway, because (mapcar
> #'foobar some-list) or (mapc #'foobar some-list) is pretty concise.
> However, when it gets more complicated than that, I tend to switch to
> LOOP:
>
> - When you have to build an anonymous function for mapcar, LOOP
> typically uses the same number of source code lines, and seems
> clearer to me. Compare:
>
> (mapcar (lambda (x) ... do something with x ...)
> some-list)
>
> (loop for x in some-list
> collect ... do something with x ...)

If that is clearer to you, then you don't understand the
basic idea of map. Map generates a list that is the same
length as the original list. Haven't you ever heard of a
one-to-one mapping?

Let's have some fun with map in Scheme.

(define (curry fun . args)
(lambda x
(apply fun (append args x))))
(define (cap f g)(lambda xs (f (apply g xs))))
(define (fork f g h)(lambda xs (f (apply g xs) (apply h xs))))

guile> (map abs '(-2 0 3))
(2 0 3)
guile> (map * '(9 8 7) '(2 3 4))
(18 24 28)
guile> (map (curry / 1) '(3 4 5 6))
(1/3 1/4 1/5 1/6)
guile> (map (fork / - +) '(9 8 7) '(2 4 5))
(7/11 1/3 1/6)

; calculate averages
guile> (map (fork / + (cap length list)) '(9 8 7) '(2 3 4) '(55 37 62))
(22 16 73/3)

>
> - I don't remember having used functions with more than one argument
> in conjunction with mapcar, so it seems to me that (mapcar #'foobar
> some-list1 some-list2) [or even more lists] is pretty uncommon.

The fact that you haven't done something does not tend to prove
that it is seldom done by others (who may be more sensible than you).


> Again, if you need to build an anonymous function with more than one
> arguments, LOOP seems clearer to me:
>
> (mapc (lambda (x y) ...)
> some-list1 some-list2)
>
> (loop for x in some-list1
> for y in some-list2
> do ...)
>
> - More often than not, the different variables actually iterate over
> different kinds of values. Recently, I needed the following costruct
> quite often:
>
> (loop for x in some-list
> for i from 0
> collect `(,x ,i))

An incredibly obfuscated hack. Why not

collect (list x i))

>
> This enumerates all elements in a list. You would have to express
> this completely manually without LOOP because none of the mapxyz
> functions help you here.

guile> (define abc '(a b c d e))
guile> (map list abc (iota (length abc)))
((a 0) (b 1) (c 2) (d 3) (e 4))

or even

guile> (zip abc (iota (length abc)))
((a 0) (b 1) (c 2) (d 3) (e 4))

>
> - The mapcan idiom to filter out certain elements is, IMHO, a hack.
> Compare:
>
> (mapcan (lambda (x)
> (when (some-property-p x)
> (list x)))
> some-list)
>
> (loop for x in some-list
> when (some-property-p x)
> collect x)

A proficient programmer would use neither.

* (remove-if-not 'evenp '(2 3 4 5))

(2 4)


>
> In this case, LOOP is more concise, and more importantly more
> explicit about what it actually does. To me, that's in fact the most
> important advantage of LOOP - it typically tells you what it does in
> a way that is almost close to natural language.

So it would be very advantageous to use COBOL instead of CL.

PROCEDURE DIVISION.
DISPLAY "hello ," WITH NO ADVANCING
DISPLAY "world!"
STOP RUN.

Yes, I think that COBOL would supply the prolixity, pomposity,
and pretentiousness upon which you dote.

Tim Bradshaw

unread,
Feb 24, 2011, 5:36:24 PM2/24/11
to
On 2011-02-24 22:14:06 +0000, WJ said:

> Haven't you ever heard of a
> one-to-one mapping?

Map does not create a one to one mapping. Indeed your example of (map
abs '(-2 0 3) is an example of it not doing so.

Marco Antoniotti

unread,
Feb 25, 2011, 4:44:27 AM2/25/11
to

WJ had not heard of one-to-one-mapping until now. That's why it took
him/her/it (*) almost 5 years to follow up on the thread. :)

cheers
--
Marco

(*) "it" because we may be in the presence of "astroturfing" :)

Tim Bradshaw

unread,
Feb 25, 2011, 5:39:10 AM2/25/11
to
On 2011-02-25 09:44:27 +0000, Marco Antoniotti said:

> WJ had not heard of one-to-one-mapping until now. That's why it took
> him/her/it (*) almost 5 years to follow up on the thread. :)

I should probably have talked about surjective mappings or something.
Not actually sure I can remember what they are (is it the same as onto?)

Andreas Eder

unread,
Feb 25, 2011, 12:04:52 PM2/25/11
to
Hi Tim,

>>>>> "Tim" == Tim Bradshaw <t...@tfeb.org> writes:

Tim> I should probably have talked about surjective mappings or something.
Tim> Not actually sure I can remember what they are (is it the same as
Tim> onto?)

Yes, that is the same.

Than, there is injective, which means f(x) = f(y) => x = y.
And bijective then is both injective and surjective.

'Andreas
--
ceterum censeo redmondinem esse delendam.

WJ

unread,
May 5, 2011, 12:57:50 PM5/5/11
to
WJ wrote:

> >
> > - The mapcan idiom to filter out certain elements is, IMHO, a hack.
> > Compare:
> >
> > (mapcan (lambda (x)
> > (when (some-property-p x)
> > (list x)))
> > some-list)
> >
> > (loop for x in some-list
> > when (some-property-p x)
> > collect x)
>
> A proficient programmer would use neither.
>
> * (remove-if-not 'evenp '(2 3 4 5))
>
> (2 4)

Arc:

arc> (keep even '(2 3 4 5))
(2 4)

0 new messages