guile-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: for-each et al


From: Ludovic Courtès
Subject: Re: for-each et al
Date: Sun, 02 Mar 2014 22:27:52 +0100
User-agent: Gnus/5.130007 (Ma Gnus v0.7) Emacs/24.3 (gnu/linux)

Hello!

Welcome back to email.  ;-)

Andy Wingo <address@hidden> skribis:

> The current boot-9 for-each for one list argument is this nastiness:
>
>   (define for-each
>     (case-lambda
>       ((f l)
>        (let for-each1 ((hare l) (tortoise l))
>          (if (pair? hare)
>              (begin
>                (f (car hare))
>                (let ((hare (cdr hare)))
>                  (if (pair? hare)
>                      (begin
>                        (when (eq? tortoise hare)
>                          (scm-error 'wrong-type-arg "for-each" "Circular 
> list: ~S"
>                                     (list l) #f))
>                        (f (car hare))
>                        (for-each1 (cdr hare) (cdr tortoise)))
>                      (for-each1 hare tortoise))))
>              (if (not (null? hare))
>                  (scm-error 'wrong-type-arg "for-each" "Not a list: ~S"
>                             (list l) #f)))))
>       ...))
>
> Terrible.  And it's slower than this:
>
>   (lambda (f l)
>     (unless (list? l)
>       (scm-error 'wrong-type-arg "for-each" "Not a list: ~S" (list l) #f))
>     (let for-each1 ((l l))
>       (unless (null? l)
>         (f (car l))
>         (for-each1 (cdr l)))))
>
> So, pop quiz: what's the difference between the two?

I think an important difference you didn’t mention is that ‘list?’ does
its list traversal in C.

> Of course, there are different levels at which this problem can be
> solved.  I think moving towards deprecation and removal of mutable pairs
> is probably a good idea, though it's really complicated and not really
> the point of this mail.  OTOH I think it's reasonable to ask for a
> consensus opinion on this implementation of "for-each":
>
>   (lambda (f l)
>     (unless (list? l)
>       (scm-error 'wrong-type-arg "for-each" "Not a list: ~S" (list l) #f))
>     (let for-each1 ((l l))
>       (unless (null? l)
>         (f (car l))
>         (for-each1 (cdr l)))))
>
> Is this a reasonable implementation?  Are we OK with the possibility for
> infinite-loops or exceptions accessing the car/cdr of what might not be
> a pair?  Alternately if we change the test to pair? are we OK with the
> possibility of the loop possibly ending silently before its time?  How
> do we deal with this kind of bug -- what's our perspective?

I’m OK with this implementation.  I’ve never found myself iterating over
a list and modifying it concurrently.

> My proposal would be that eventually, I don't know how, but Guile should
> remove all use of mutable pairs in its own code.  There's not much
> set-car!/set-cdr! in Scheme so it's not that big of a deal.  Therefore
> in light of that long-term goal, we should write library code as if
> pairs were immutable, and therefore the test-then-iterate example is
> fine code.
>
> WDYT?

I’m all in favor of immutable pairs.  However, I expect that a lot of
code out there relies on it.

Moving set-car! and set-cdr! to a different module like in R6 may be a
good first (or second) step.

Thanks,
Ludo’.




reply via email to

[Prev in Thread] Current Thread [Next in Thread]