• Re: Loop

    From B. Pym@21:1/5 to Gareth McCaughan on Sat Sep 7 19:50:29 2024
    XPost: comp.lang.scheme

    Gareth McCaughan wrote:

    It's not a better algorithm. The point is that because it's
    more concise you are less likely to get lost in details, and
    therefore more likely to be able to spot algorithmic improvements.
    If you write

    (loop for x from a to b by d collect x)

    rather than

    (do ((j a (+ j d))
    (result nil))
    ((>= j b) (nreverse result))
    (push j result))


    Bad. Very bad.

    (do ((x 20 (+ x 2))
    (r '() (cons x r)))
    ((> x 30) (reverse r)))

    ===>
    (20 22 24 26 28 30)

    Shorter:

    (do ((x 30 (- x 2))
    (r '() (cons x r)))
    ((< x 20) r))


    And is "nreverse" actually faster than "reverse"?

    On page 222 in "ANSI Common Lisp" Paul Graham writes:

    "In Lisp implementations with bad garbage collectors, programs that
    cons a lot tend to run slowly. Until recently, most Lisp
    implementations have had bad garbage collectors, and so it has become
    a tradition that efficient programs should cons as little as possible.
    Recent developments have turned this conventional wisdom on its head.
    Some implementations now have such sophisticated garbage colletors
    that it is faster to cons up new objects and throw them away than it
    is to recycle them."



    then

    - it's about half as much code, and 1/4 as many lines with
    most people's indentation conventions;

    - it's therefore twice as fast to type

    - it takes quite a lot less than half as long to *write*
    (or at least it does for me; I found that I had to think
    for the best part of a second at a couple of places while
    writing the iterative version)

    - it's quicker to read

    Testing:

    (loop for x from 20 to 30 by 2 collect x)

    (20 22 24 26 28 30)

    Shorter:

    Gauche Scheme

    Function: unfold end-test key gen-next-seed seed

    (use srfi-1) ;; unfold

    ;; pa$ is partial application (currying).
    ;; Using + for identity.
    (unfold (pa$ < 30) + (pa$ + 2) 20)
    ===>
    (20 22 24 26 28 30)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From B. Pym@21:1/5 to Gareth McCaughan on Fri Jun 27 22:27:30 2025
    Gareth McCaughan wrote:

    It's not a better algorithm. The point is that because it's
    more concise you are less likely to get lost in details, and
    therefore more likely to be able to spot algorithmic improvements.
    If you write

    (loop for x from a to b by d collect x)

    rather than

    (do ((j a (+ j d))
    (result nil))
    ((>= j b) (nreverse result))
    (push j result))

    That's a rather poor do loop.

    (do ((x 30 (- x 2))
    (r '() (cons x r)))
    ((< x 20) r))

    ===>
    (20 22 24 26 28 30)


    Gauche Scheme:

    (lrange 20 31 2)

    ===>
    (20 22 24 26 28 30)


    How about using "unfold" from SRFI-1?

    (use srfi-1)

    (unfold (cut > <> 30) identity (cut + <> 2) 20)

    ===>
    (20 22 24 26 28 30)


    (use srfi-42) ;; list-ec
    (list-ec (: x 20 31 2) x)

    ===>
    (20 22 24 26 28 30)

    Less condensed:

    (list-ec (:range x 20 31 2) x)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)