From: franks on
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.
>
> > 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.

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

From: Pascal Costanza on
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.


Pascal

--
My website: http://p-cos.net
Closer to MOP & ContextL:
http://common-lisp.net/project/closer/
From: Rob Warnock on
Pascal Costanza <pc(a)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)
>


-Rob

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

From: Lars Brinkhoff on
rpw3(a)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.
From: Rob Warnock on
Lars Brinkhoff <lars.spam(a)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.


-Rob

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

 |  Next  |  Last
Pages: 1 2
Prev: You want Cells doc?
Next: Remote debugging