• matching n objects in a list with pattern matcher

    From Robert L.@21:1/5 to Robert L. on Sat Aug 31 15:32:21 2019
    On 8/31/2019, Robert L. wrote:

    On 6/19/2019, Felix wrote:

    I have this function:

    (use-module (ice-9 match))

    (define (chunk4 obj)
    (let chunker ((in obj) (out '()))
    (match in
    ((a b c d . rest) (chunker rest (cons (list a b c d) out)))
    (() (reverse out))
    (tail (reverse (cons tail out))))))

    and I am trying to figure out how to generalize it to
    but the only solution I have come up with so far is:

    (define (chunk obj n)
    (let chunker ((in obj) (out '()))
    (match in
    (() (reverse out))
    ((? (lambda (l) (< (length l) n)) tail) (reverse (cons tail out)))

    Taking the length of the list being chunked isn't efficient.


    (long (chunker (drop n long) (cons (take n long) out))))))

    Is there a way to write a pattern to match a
    list of n items for the second function?

    Tested in Gauche Scheme.

    (define (chunk items n)
    (let go ((in items) (out '()))
    (if (null? in)
    (reverse out)
    (receive
    (a b)
    (guard (_ (#t (values in '()))) (split-at in n))
    (go b (cons a out))))))


    It works in Racket after:

    (require srfi/8) ;; receive
    (require srfi/34) ;; guard

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Robert L.@21:1/5 to Robert L. on Sun Sep 1 05:05:26 2019
    On 8/31/2019, Robert L. wrote:

    On 6/19/2019, Felix wrote:

    I have this function:

    (use-module (ice-9 match))

    (define (chunk4 obj)
    (let chunker ((in obj) (out '()))
    (match in
    ((a b c d . rest) (chunker rest (cons (list a b c d) out)))
    (() (reverse out))
    (tail (reverse (cons tail out))))))

    and I am trying to figure out how to generalize it to
    but the only solution I have come up with so far is:

    (define (chunk obj n)
    (let chunker ((in obj) (out '()))
    (match in
    (() (reverse out))
    ((? (lambda (l) (< (length l) n)) tail) (reverse (cons tail out)))

    Taking the length of the list being chunked isn't efficient.


    (long (chunker (drop n long) (cons (take n long) out))))))

    Is there a way to write a pattern to match a
    list of n items for the second function?

    Tested in Gauche Scheme.

    (define (chunk items n)
    (let go ((in items) (out '()))
    (if (null? in)
    (reverse out)
    (receive
    (a b)
    (guard (_ (#t (values in '()))) (split-at in n))
    (go b (cons a out))))))


    In Gauche Scheme, take* and drop* are safe versions that
    do not raise an exception when the list is too short.

    Gauche took "unfold" from SRFI-1 and "cut" from SRFI-26.

    (cut take* <> n)
    is equivalent to
    (lambda (xs) (take* xs n)).

    (define (chunk items n)
    (unfold
    null?
    (cut take* <> n)
    (cut drop* <> n)
    items))

    gosh> (chunk (iota 8) 6)
    ((0 1 2 3 4 5) (6 7))
    gosh> (chunk (iota 9) 3)
    ((0 1 2) (3 4 5) (6 7 8))
    gosh> (chunk (iota 9) 1)
    ((0) (1) (2) (3) (4) (5) (6) (7) (8))
    gosh> (chunk () 1)
    ()

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Robert L.@21:1/5 to Robert L. on Sun Sep 1 07:40:27 2019
    On 8/31/2019, Robert L. wrote:

    (define (chunk items n)
    (unfold
    null?
    (cut take* <> n)
    (cut drop* <> n)
    items))

    Needs this first:

    (use srfi-1) ;; unfold

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Robert L.@21:1/5 to Felix on Sun Sep 1 15:27:14 2019
    On 6/19/2019, Felix wrote:

    (define (chunk obj n)
    (let chunker ((in obj) (out '()))
    (match in
    (() (reverse out))
    ((? (lambda (l) (< (length l) n)) tail) (reverse (cons tail out)))
    (long (chunker (drop n long) (cons (take n long) out))))))

    Using generators in Gauche Scheme.

    (use srfi-158) ;; generators and accumulators

    (define (chunk items n)
    (let ((gen (list->generator items)))
    (generator->list
    (gtake-while pair? (cut generator->list gen n)))))

    Cuter and shorter:

    (define (chunk items n)
    (generator->list
    (gtake-while pair?
    (cute generator->list (list->generator items) n))))

    "cute" is "cut with evaluated non-slots".

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Robert L.@21:1/5 to Robert L. on Sun Sep 1 20:14:42 2019
    On 9/1/2019, Robert L. wrote:

    On 6/19/2019, Felix wrote:

    (define (chunk obj n)
    (let chunker ((in obj) (out '()))
    (match in
    (() (reverse out))
    ((? (lambda (l) (< (length l) n)) tail) (reverse (cons tail out)))
    (long (chunker (drop n long) (cons (take n long) out))))))

    Using generators in Gauche Scheme.

    (use srfi-158) ;; generators and accumulators

    (define (chunk items n)
    (let ((gen (list->generator items)))
    (generator->list
    (gtake-while pair? (cut generator->list gen n)))))

    Cuter and shorter:

    (define (chunk items n)
    (generator->list
    (gtake-while pair?
    (cute generator->list (list->generator items) n))))

    "cute" is "cut with evaluated non-slots".

    SRFI-158 has "ggroup", which makes it trivial.

    (define (chunk items n)
    (generator->list (ggroup (list->generator items) n)))

    If you may want the last group to be padded:

    (define (chunk items n :optional padding)
    (generator->list
    (ggroup (list->generator items) n padding)))

    gosh> (chunk (iota 9) 4)
    ((0 1 2 3) (4 5 6 7) (8))
    gosh> (chunk (iota 9) 4 -99)
    ((0 1 2 3) (4 5 6 7) (8 -99 -99 -99))

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Felix@21:1/5 to Robert L. on Wed Sep 4 19:33:10 2019
    On Saturday, August 31, 2019 at 6:41:58 AM UTC-4, Robert L. wrote:


    Taking the length of the list being chunked isn't efficient.

    That's why it takes so long for big lists compared to the fixed chunker

    I rewrote it like:

    (define (chunk.v2 obj n)
    (let recur ((left obj) (out '()) (len (length obj)))
    (cond
    ((null? left) (reverse out))
    ((< len n) (reverse (cons obj out)))
    (else (recur (drop left n)
    (cons (take left n) out)
    (- len n))))))

    and now it is just as fast. I will look into these other srfis. Thanks!

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