unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
From: Andy Wingo <wingo@pobox.com>
To: ludo@gnu.org (Ludovic Courtès)
Cc: guile-devel@gnu.org
Subject: Re: for-each et al
Date: Tue, 04 Mar 2014 21:30:25 +0100	[thread overview]
Message-ID: <87wqg9ogf2.fsf@pobox.com> (raw)
In-Reply-To: <87r46ks33b.fsf@gnu.org> ("Ludovic Courtès"'s message of "Sun, 02 Mar 2014 22:27:52 +0100")

On Sun 02 Mar 2014 22:27, ludo@gnu.org (Ludovic Courtès) writes:

> Welcome back to email.  ;-)

Thank you :)  This makes my first round-trip ;)

>>   (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.

That's true.  Let's call the above version for-each*.  Then we have
for-each**, which is the same except it calls list*, which is:

(define (list*? l)
  (let lp ((hare l) (tortoise l))
    (or (null? hare)
        (and (pair? hare)
             (let ((hare (cdr hare)))
               (or (null? hare)
                   (and (pair? hare)
                        (not (eq? tortoise hare))
                        (lp (cdr hare) (cdr tortoise)))))))))

Then we have:

  scheme@(guile-user)> (define l (iota 100000000))
  scheme@(guile-user)> ,time (for-each** (lambda (x) x) l)
  ;; 3.228201s real time, 3.223919s run time.  0.000000s spent in GC.
  scheme@(guile-user)> ,time (for-each* (lambda (x) x) l)
  ;; 2.356612s real time, 2.353496s run time.  0.000000s spent in GC.
  scheme@(guile-user)> ,time (for-each (lambda (x) x) l)
  ;; 3.142366s real time, 3.126806s run time.  0.000000s spent in GC.

So the overhead of traversing the list twice is negligible in the worst
case, and probably we still gain once the compiler gets better.

>>   (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)))))

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

Yeah it's something that no one in their right mind does.  But still we
should have some kind of statement about what we guarantee -- currently
the code is resilient to concurrent mutation, and we'd be relaxing that.

> 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.

Brainstorming possibilities:

  * Deprecate set-car!/set-cdr! (replacement would be mutable cells in
    the car/cdr; currently called variables, but could be called boxes)

  * Introducing a #!lang facility, and having programs with #!lang make
    immutable pairs

  * ?

It's completely possible to remove mutable pair usage in Guile, but
what's not clear is how to migrate our users.  I assume that we would
want to make Guile's core operations only operate on immutable pairs;
how big would the mutable pair libraries have to be?

Could we forsake R6RS/R7RS and only do immutable pairs?  (I would be OK
with that.  In that case R5RS would run in its own environment.)

Dunno, just some thoughts.  Deprecating set-car!/set-cdr! would be an
easy first step, if we planned to make further steps.

Andy
-- 
http://wingolog.org/



  reply	other threads:[~2014-03-04 20:30 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-03-02 15:55 for-each et al Andy Wingo
2014-03-02 21:27 ` Ludovic Courtès
2014-03-04 20:30   ` Andy Wingo [this message]
2014-03-04 22:35     ` Ludovic Courtès
2014-03-05 19:59       ` Andy Wingo
2014-03-05 22:32         ` Ludovic Courtès

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/guile/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87wqg9ogf2.fsf@pobox.com \
    --to=wingo@pobox.com \
    --cc=guile-devel@gnu.org \
    --cc=ludo@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).