|
Prev: You want Cells doc?
Next: Remote debugging
From: franks on 3 Aug 2006 17:28 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 3 Aug 2006 18:03 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 4 Aug 2006 00:52 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 4 Aug 2006 03:01 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 4 Aug 2006 03:42
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 |