unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
From: Amirouche Boubekki <amirouche@hypermove.net>
To: Guile User <guile-user@gnu.org>
Cc: guile-user <guile-user-bounces+amirouche=hypermove.net@gnu.org>
Subject: Re: optimizing lazy sequences: srfi-41 vs delayed continuation with values + promise vs delayed continuation with cons + lambda
Date: Sun, 25 Feb 2018 15:30:16 +0100	[thread overview]
Message-ID: <f1a6e788ede369278b8582188b571368@hypermove.net> (raw)
In-Reply-To: <f560f163030595b76e32c74066e8c017@hypermove.net>

On 2018-02-25 15:16, Amirouche Boubekki wrote:
> Hello all,
> 
> I know it's not good to optimize first, but I got into it
> and now I need to know.
> 
> A few months ago, I created a lazy sequence library that retains
> history based on delayed continuation, it can be summarized
> as follow:
> 
> (define-public (list->traversi lst)
>   (let loop ((lst lst))
>     (lambda ()
>       (if (null? lst)
>           '()
>           ;; here the car of the pair contains the first value
>           ;; and an empty list as history
>           (cons (cons (car lst) '()) (loop (cdr lst)))))))
> 
> (define-public (traversi->list traversi)
>   (let loop ((traversi traversi)
>              (out '()))
>     (match (traversi)
>       ('() (reverse out))
>       ((item . next) (loop next (cons (car item) out))))))
> 
> (define-public (traversi-map proc traversi)
>   (let loop ((traversi traversi))
>     (lambda ()
>       (match (traversi)
>         ('() '())
>         ((item . next) (cons (cons (proc (car item)) item) (loop 
> next)))))))
> 
> They are other procedures, but that is the gist of it.
> 
> I tested it on a parser combinator for csv and it seemed much
> faster than the srfi-41 based parser combinators [0].
> 
> [0] https://git.dthompson.us/guile-parser-combinators.git
> 
> Now, I got another idea what if I replace the 'cons' returned
> by the traversi procedures by 'values' and replace the
> lambda with 'delay' with some use of 'force' at the correct
> places. It will result in the following procedures:
> 
> (define-public (list->stream lst)
>   (let loop ((lst lst))
>     (if (null? lst)
>         (delay (values #f #f))
>         (delay (values (car lst) (loop (cdr lst)))))))
> 
> (define-public (stream->list stream)
>   (let loop ((stream stream)
>              (out '()))
>     (call-with-values (lambda () (force stream))
>       (lambda (value next)
>         (if next
>             (loop next (cons value out))
>             (reverse! out))))))
> 
> (define-public (stream-map proc stream)
>   (let loop ((stream stream))
>     (call-with-values (lambda () (force stream))
>       (lambda (value next)
>         (if next
>             (delay (values (proc value) (loop next)))
>             (delay (values #f #f)))))))
> 
> I tested those procedures in the REPL with ,time and
> the results are not conclusive:
> 
> scheme@(guile-user)> (define (nop o) #t)
> 
> 
> scheme@(guile-user)> ,time (nop (traversi->list (traversi-map (lambda
> (x) (1+ x)) (list->traversi (iota (expt 2 10))))))
> $1 = #t
> ;; 0.028090s real time, 0.037698s run time.  0.012421s spent in GC.
> scheme@(guile-user)> ,time (nop (traversi->list (traversi-map (lambda
> (x) (1+ x)) (list->traversi (iota (expt 2 10))))))
> $2 = #t
> ;; 0.025622s real time, 0.025614s run time.  0.000000s spent in GC.
> scheme@(guile-user)> ,time (nop (traversi->list (traversi-map (lambda
> (x) (1+ x)) (list->traversi (iota (expt 2 10))))))
> $3 = #t
> ;; 0.034165s real time, 0.034146s run time.  0.000000s spent in GC.
> 
> scheme@(guile-user)> ,time (nop (stream->list (stream-map (lambda (x)
> (1+ x)) (list->stream (iota (expt 2 10))))))
> $4 = #t
> ;; 0.031616s real time, 0.041882s run time.  0.014514s spent in GC.
> scheme@(guile-user)> ,time (nop (stream->list (stream-map (lambda (x)
> (1+ x)) (list->stream (iota (expt 2 10))))))
> $5 = #t
> ;; 0.026148s real time, 0.026141s run time.  0.000000s spent in GC.
> scheme@(guile-user)> ,time (nop (stream->list (stream-map (lambda (x)
> (1+ x)) (list->stream (iota (expt 2 10))))))
> $6 = #t
> ;; 0.028477s real time, 0.037107s run time.  0.011057s spent in GC.

I forgot the srfi-41 because they are worse:

scheme@(guile-user)> (use-modules (srfi srfi-41))scheme@(guile-user)> 
(define (nop o) #t)
scheme@(guile-user)> ,time (nop (stream->list (stream-map (lambda (x) 
(1+ x)) (list->stream (iota (expt 2 10))))))
$1 = #t
;; 0.034429s real time, 0.043788s run time.  0.012689s spent in GC.
scheme@(guile-user)> ,time (nop (stream->list (stream-map (lambda (x) 
(1+ x)) (list->stream (iota (expt 2 10))))))
$2 = #t
;; 0.033329s real time, 0.041973s run time.  0.010852s spent in GC.
scheme@(guile-user)> ,time (nop (stream->list (stream-map (lambda (x) 
(1+ x)) (list->stream (iota (expt 2 10))))))
$3 = #t
;; 0.056261s real time, 0.064563s run time.  0.010440s spent in GC.



> Q: What in theory should be faster?
> 
> Q: How can I test / proove that one approach must be faster?
> 
> From the usability & readability point of view I find the
> values + promise much more readable and easier to code.
> 
> TIA!

-- 
Amirouche ~ amz3 ~ http://www.hyperdev.fr



  reply	other threads:[~2018-02-25 14:30 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-02-25 14:16 optimizing lazy sequences: srfi-41 vs delayed continuation with values + promise vs delayed continuation with cons + lambda Amirouche Boubekki
2018-02-25 14:30 ` Amirouche Boubekki [this message]
2018-02-25 22:39   ` Amirouche Boubekki
2018-02-25 23:31     ` Amirouche Boubekki
2018-03-02 23:22 ` Mark H Weaver

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=f1a6e788ede369278b8582188b571368@hypermove.net \
    --to=amirouche@hypermove.net \
    --cc=guile-user-bounces+amirouche=hypermove.net@gnu.org \
    --cc=guile-user@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).