diff --git a/scsh/lib/list-lib.scm b/scsh/lib/list-lib.scm index c042618..2491355 100644 --- a/scsh/lib/list-lib.scm +++ b/scsh/lib/list-lib.scm @@ -26,15 +26,19 @@ ;;; take drop ;;; take-right drop-right ;;; take! drop-right! +;;; split-at split-at! ;;; last last-pair ;;; zip unzip1 unzip2 unzip3 unzip4 unzip5 ;;; count -;;; append! append-reverse append-reverse! -;;; unfold fold fold-right pair-fold pair-fold-right reduce reduce-right +;;; append! append-reverse append-reverse! concatenate concatenate! +;;; unfold fold pair-fold reduce +;;; unfold-right fold-right pair-fold-right reduce-right ;;; append-map append-map! map! pair-for-each filter-map map-in-order ;;; filter partition remove ;;; filter! partition! remove! ;;; find find-tail any every list-index +;;; take-while drop-while take-while! +;;; span break span! break! ;;; delete delete! ;;; alist-cons alist-copy ;;; delete-duplicates delete-duplicates! @@ -246,7 +250,7 @@ ;;; (cons* a1 a2 ... an) = (cons a1 (cons a2 (cons ... an))) ;;; (cons* a1) = a1 (cons* a1 a2 ...) = (cons a1 (cons* a2 ...)) ;;; -;;; (cons first (unfold-right not-pair? car cdr rest values)) +;;; (cons first (unfold not-pair? car cdr rest values)) (define (cons* first . rest) (let recur ((x first) (rest rest)) @@ -254,7 +258,7 @@ (cons x (recur (car rest) (cdr rest))) x))) -;;; (unfold-right not-pair? car cdr lis values) +;;; (unfold not-pair? car cdr lis values) (define (list-copy lis) (let recur ((lis lis)) @@ -571,6 +575,21 @@ ; lis))) ; (list-tail lis k))) +(define (split-at x k) + (check-arg integer? k split-at) + (let recur ((lis x) (k k)) + (if (zero? k) (values '() lis) + (receive (prefix suffix) (recur (cdr lis) (- k 1)) + (values (cons (car lis) prefix) suffix))))) + +(define (split-at! x k) + (check-arg integer? k split-at!) + (if (zero? k) (values '() x) + (let* ((prev (drop x (- k 1))) + (suffix (cdr prev))) + (set-cdr! prev '()) + (values x suffix)))) + (define (last lis) (car (last-pair lis))) @@ -625,8 +644,8 @@ (cons (car (cddddr elt)) e))))))) -;;; append! append-reverse append-reverse! -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; append! append-reverse append-reverse! concatenate concatenate! +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define (append! . lists) ;; First, scan through lists looking for a non-empty one. @@ -679,6 +698,8 @@ (lp next-rev rev-head))))) +(define (concatenate lists) (reduce-right append '() lists)) +(define (concatenate! lists) (reduce-right append! '() lists)) ;;; Fold/map internal utilities ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -778,25 +799,25 @@ ;;; fold/unfold ;;;;;;;;;;;;;;; -(define (unfold p f g seed . maybe-tail) - (check-arg procedure? p unfold) - (check-arg procedure? f unfold) - (check-arg procedure? g unfold) +(define (unfold-right p f g seed . maybe-tail) + (check-arg procedure? p unfold-right) + (check-arg procedure? f unfold-right) + (check-arg procedure? g unfold-right) (let lp ((seed seed) (ans (:optional maybe-tail '()))) (if (p seed) ans (lp (g seed) (cons (f seed) ans))))) -(define (unfold-right p f g seed . maybe-tail-gen) - (check-arg procedure? p unfold-right) - (check-arg procedure? f unfold-right) - (check-arg procedure? g unfold-right) +(define (unfold p f g seed . maybe-tail-gen) + (check-arg procedure? p unfold) + (check-arg procedure? f unfold) + (check-arg procedure? g unfold) (if (pair? maybe-tail-gen) (let ((tail-gen (car maybe-tail-gen))) (if (pair? (cdr maybe-tail-gen)) - (apply error "Too many arguments" unfold-right p f g seed maybe-tail-gen) + (apply error "Too many arguments" unfold p f g seed maybe-tail-gen) (let recur ((seed seed)) (if (p seed) (tail-gen seed) @@ -1252,11 +1273,8 @@ (filter! (lambda (elt) (not (= key (car elt)))) alist))) -;;; find find-tail any every list-index -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; ANY returns the first true value produced by PRED. -;;; FIND returns the first list elt passed by PRED. +;;; find find-tail take-while drop-while span break any every list-index +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define (find pred list) (cond ((find-tail pred list) => car) @@ -1269,6 +1287,58 @@ (if (pred (car list)) list (lp (cdr list)))))) +(define (take-while pred lis) + (check-arg procedure? pred take-while) + (let recur ((lis lis)) + (if (null-list? lis) '() + (let ((x (car lis))) + (if (pred x) + (cons x (recur (cdr lis))) + '()))))) + +(define (drop-while pred lis) + (check-arg procedure? pred drop-while) + (let lp ((lis lis)) + (if (null-list? lis) '() + (if (pred (car lis)) + (lp (cdr lis)) + lis)))) + +(define (take-while! pred lis) + (check-arg procedure? pred take-while!) + (if (or (null-list? lis) (not (pred (car lis)))) '() + (begin (let lp ((prev lis) (rest (cdr lis))) + (if (pair? rest) + (let ((x (car rest))) + (if (pred x) (lp rest (cdr rest)) + (set-cdr! prev '()))))) + lis))) + +(define (span pred lis) + (check-arg procedure? pred span) + (let recur ((lis lis)) + (if (null-list? lis) (values '() '()) + (let ((x (car lis))) + (if (pred x) + (receive (prefix suffix) (recur (cdr lis)) + (values (cons x prefix) suffix)) + (values '() lis)))))) + +(define (span! pred lis) + (check-arg procedure? pred span!) + (if (or (null-list? lis) (not (pred (car lis)))) (values '() lis) + (let ((suffix (let lp ((prev lis) (rest (cdr lis))) + (if (null-list? rest) rest + (let ((x (car rest))) + (if (pred x) (lp rest (cdr rest)) + (begin (set-cdr! prev '()) + rest))))))) + (values lis suffix)))) + + +(define (break pred lis) (span (lambda (x) (not (pred x))) lis)) +(define (break! pred lis) (span! (lambda (x) (not (pred x))) lis)) + (define (any pred lis1 . lists) (check-arg procedure? pred any) (if (pair? lists) @@ -1315,8 +1385,6 @@ (if (null-list? tail) (pred head) ; Last PRED app is tail call. (and (pred head) (lp (car tail) (cdr tail)))))))) - - (define (list-index pred lis1 . lists) (check-arg procedure? pred list-index) diff --git a/scsh/lib/list-pack.scm b/scsh/lib/list-pack.scm index 6fa562a..a2f4b67 100644 --- a/scsh/lib/list-pack.scm +++ b/scsh/lib/list-pack.scm @@ -13,17 +13,21 @@ ;;; take drop ;;; take-right drop-right ;;; take! drop-right! +;;; take-while drop-while take-while! +;;; split-at split-at! +;;; span break +;;; span! break! ;;; last last-pair ;;; length+ -;;; append! reverse! append-reverse append-reverse! +;;; append! reverse! append-reverse append-reverse! concatenate concatenate! ;;; zip unzip1 unzip2 unzip3 unzip4 unzip5 ;;; count ;;; unfold unfold-right ;;; fold unfold pair-fold reduce ;;; fold-right unfold-right pair-fold-right reduce-right ;;; append-map append-map! map! pair-for-each filter-map map-in-order -;;; filter partition remove -;;; filter! partition! remove! +;;; filter partition remove +;;; filter! partition! remove! ;;; find find-tail any every list-index ;;; delete delete! delete-duplicates delete-duplicates! ;;; alist-cons alist-copy @@ -87,6 +91,9 @@ ((take drop take-right drop-right take! drop-right!) (proc (:value :exact-integer) :value)) + ((split-at split-at!) + (proc (:value :exact-integer) (some-values :value :value))) + (last (proc (:pair) :value)) (last-pair (proc (:pair) :pair)) @@ -94,6 +101,7 @@ (append! (proc (:value &rest :value) :value)) (reverse! (proc (:value) :value)) ((append-reverse append-reverse!) (proc (:value :value) :value)) + ((concatenate concatenate!) (proc (:value) :value)) (zip (proc (:value &rest :value) :value)) (unzip1 (proc (:value) :value)) @@ -138,6 +146,12 @@ ((find find-tail) (proc ((proc (:value) :boolean) :value) :value)) + ((take-while take-while! drop-while) + (proc ((proc (:value) :boolean) :value) :value)) + + ((span break span! break!) + (proc ((proc (:value) :boolean) :value) (some-values :value :value))) + ((any every) (proc ((proc (:value &rest :value) :value) :value &rest :value) :value)) diff --git a/scsh/lib/srfi-1.html b/scsh/lib/srfi-1.html index 8457db0..125ae20 100644 --- a/scsh/lib/srfi-1.html +++ b/scsh/lib/srfi-1.html @@ -253,7 +253,7 @@ implementation. I have placed this source on the Net with an unencumbered,
filter!
avoid unnecessary,
@@ -310,15 +310,16 @@ extended R5RS
take drop
take-right drop-right
take! drop-right!
+split-at split-at!
last last-pair
-length length+ -append reverse -append! reverse! +append concatenate reverse +append! concatenate! reverse! append-reverse append-reverse! zip unzip1 unzip2 unzip3 unzip4 unzip5 count @@ -348,6 +349,8 @@ extended R5RS find find-tail any every list-index +take-while drop-while take-while! +span break span! break!
The linear-update procedures in this library are
-take! drop-right!
-append! reverse! append-reverse!
+take! drop-right! split-at!
+append! concatenate! reverse! append-reverse!
append-map! map!
filter! partition! remove!
+take-while! span! break!
delete! alist-delete! delete-duplicates!
lset-adjoin! lset-union! lset-intersection!
lset-difference! lset-xor! lset-diff+intersection!
@@ -1242,6 +1246,33 @@ partition the entire universe of Scheme values.
+
+
+
+split-at
x i -> [list object]
+
+
+split-at!
x i -> [list object]
+
+ split-at
splits the list x
+ at index i, returning a list of the
+ first i elements, and the remaining tail. It is equivalent
+ to
+
+(values (take x i) (drop x i))
+
+ split-at!
is the linear-update variant. It is allowed, but not
+ required, to alter the argument list to produce the result.
+
+(split-at '(a b c d e f g h) 3) =>
+ (a b c)
+ (d e f g h)
+
+
+
-Miscellaneous: length, append, reverse, zip & count
+Miscellaneous: length, append, concatenate, reverse, zip & count
+-
+
+
concatenate
list-of-lists -> value
+-
+
+
concatenate!
list-of-lists -> value
+ -
+ These functions append the elements of their argument together.
+ That is,
concatenate
returns
+
+(apply append list-of-lists)
+
+ or, equivalently,
+
+(reduce-right append '() list-of-lists)
+
+
+ concatenate!
is the linear-update variant, defined in
+ terms of append!
instead of append
.
+
+
+ Note that some Scheme implementations do not support passing more than a
+ certain number (e.g., 64) of arguments to an n-ary procedure.
+ In these implementations, the (apply append ...)
idiom
+ would fail when applied to long lists,
+ but concatenate
would continue to function properly.
+
+
+ As with append
and append!
,
+ the last element of the input list may be any value at all.
+
@@ -1643,6 +1708,11 @@ Otherwise, return (fold f (car list) (cdr li
Note: MIT Scheme and Haskell flip F's arg order for their reduce
and
fold
functions.
+
+;; Take the max of a list of non-negative integers.
+(reduce max 0 nums) ; i.e., (apply max 0 nums)
+
+
@@ -1661,14 +1731,103 @@ Otherwise, return (fold f (car list) (cdr li
...in other words, we compute
(fold-right f ridentity list)
.
+
+;; Append a bunch of lists together.
+;; I.e., (apply append list-of-lists)
+(reduce-right append '() list-of-lists)
+
+
-
-
unfold
p f g seed [tail] -> list
+unfold
p f g seed [tail-gen] -> list
-
-
unfold
constructs a list with the following loop:
+unfold
is best described by its basic recursion:
+
+(unfold p f g seed) =
+ (if (p seed) (tail-gen seed)
+ (cons (f seed)
+ (unfold p f g (g seed))))
+
+
+- p
- Determines when to stop unfolding.
+
- f
- Maps each seed value to the corresponding list element.
+
- g
- Maps each seed value to next seed value.
+
- seed
- The "state" value for the unfold.
+
- tail-gen
- Creates the tail of the list;
+ defaults to
(lambda (x) '())
+
+
+ In other words, we use g to generate a sequence of seed values
+
+seed, g(seed), g2(seed), g3(seed), ...
+
+ These seed values are mapped to list elements by f,
+ producing the elements of the result list in a left-to-right order.
+ P says when to stop.
+
+
+ unfold
is the fundamental recursive list constructor,
+ just as fold-right
is
+ the fundamental recursive list consumer.
+ While unfold
may seem a bit abstract
+ to novice functional programmers, it can be used in a number of ways:
+
+
+;; List of squares: 1^2 ... 10^2
+(unfold (lambda (x) (> x 10))
+ (lambda (x) (* x x))
+ (lambda (x) (+ x 1))
+ 1)
+
+(unfold null-list? car cdr lis) ; Copy a proper list.
+
+;; Read current input port into a list of values.
+(unfold eof-object? values (lambda (x) (read)) (read))
+
+;; Copy a possibly non-proper list:
+(unfold not-pair? car cdr lis
+ values)
+
+;; Append HEAD onto TAIL:
+(unfold null-list? car cdr head
+ (lambda (x) tail))
+
+
+ Interested functional programmers may enjoy noting that
+ fold-right
and unfold
+ are in some sense inverses.
+ That is, given operations knull?, kar,
+ kdr, kons, and knil satisfying
+
+(kons (kar x) (kdr x))
= x
+ and
+(knull? knil)
= #t
+
+ then
+
+(fold-right kons knil (unfold knull? kar kdr x))
= x
+
+ and
+
+(unfold knull? kar kdr (fold-right kons knil x))
= x.
+
+
+ This combinator sometimes is called an "anamorphism;" when an
+ explicit tail-gen procedure is supplied, it is called an
+ "apomorphism."
+
+
+
+ -
+
+
unfold-right
p f g seed [tail] -> list
+ -
+
unfold-right
constructs a list with the following loop:
(let lp ((seed seed) (lis tail))
(if (p seed) lis
@@ -1683,103 +1842,39 @@ Otherwise, return (fold f (car list) (cdr li
- tail
- list terminator; defaults to
'()
.
- unfold
is the fundamental iterative list constructor,
+ In other words, we use g to generate a sequence of seed values
+
+seed, g(seed), g2(seed), g3(seed), ...
+
+ These seed values are mapped to list elements by f,
+ producing the elements of the result list in a right-to-left order.
+ P says when to stop.
+
+
+ unfold-right
is the fundamental iterative list constructor,
just as fold
is the
fundamental iterative list consumer.
- While unfold
may seem a bit abstract
- to novice functional programmers, it can be used in a number of ways:
-
-;; List of squares: 1^2 ... 10^2
-(unfold zero?
- (lambda (x) (* x x))
- (lambda (x) (- x 1))
- 10)
-
-;; Reverse a proper list.
-(unfold null-list? car cdr lis)
-
-;; Read current input port into a list of values.
-(unfold eof-object? values (lambda (x) (read)) (read))
-
-;; (append-reverse rev-head tail)
-(unfold null-list? car cdr rev-head tail)
-
-
- Interested functional programmers may enjoy noting that
- fold
and unfold
- are in some sense inverses.
- That is, given operations knull?, kar,
- kdr, kons, and knil satisfying
-
-(kons (kar x) (kdr x))
= x
- and
-(knull? knil)
= #t
-
- then
-
-(fold kons knil (unfold knull? kar kdr x))
= x
-
- and
-
-(unfold knull? kar kdr (fold kons knil x))
= x.
-
-
- This combinator presumably has some pretentious mathematical name;
- interested readers are invited to communicate it to the author.
-
-
-
-
-
-unfold-right
p f g seed [tail-gen] -> list
-
-unfold
is best described by its basic recursion:
-
-(unfold-right p f g seed) =
- (if (p seed) (tail-gen seed)
- (cons (f seed)
- (unfold-right p f g (g seed))))
-
-
-- p
- Determines when to stop unfolding.
-
- f
- Maps each seed value to the corresponding list element.
-
- g
- Maps each seed value to next seed value.
-
- seed
- The "state" value for the unfold.
-
- tail-gen
- Creates the tail of the list;
- defaults to
(lambda (x) '())
-
-
- unfold-right
is the fundamental recursive list constructor,
- just as fold-right
is
- the fundamental recursive list consumer.
While unfold-right
may seem a bit abstract
to novice functional programmers, it can be used in a number of ways:
-
;; List of squares: 1^2 ... 10^2
-(unfold-right (lambda (x) (> x 10))
+(unfold-right zero?
(lambda (x) (* x x))
- (lambda (x) (+ x 1))
- 1)
-
-(unfold-right null-list? car cdr lis) ; Copy a proper list.
+ (lambda (x) (- x 1))
+ 10)
+
+;; Reverse a proper list.
+(unfold-right null-list? car cdr lis)
;; Read current input port into a list of values.
(unfold-right eof-object? values (lambda (x) (read)) (read))
-;; Copy a possibly non-proper list:
-(unfold-right not-pair? car cdr lis
- values)
-
-;; Append HEAD onto TAIL:
-(unfold-right null-list? car cdr head
- (lambda (x) tail))
+;; (append-reverse rev-head tail)
+(unfold-right null-list? car cdr rev-head tail)
Interested functional programmers may enjoy noting that
- fold-right
and unfold-right
+ fold
and unfold-right
are in some sense inverses.
That is, given operations knull?, kar,
kdr, kons, and knil satisfying
@@ -1790,17 +1885,15 @@ Otherwise, return (fold f (car list) (cdr li
(fold-right kons knil (unfold-right knull? kar kdr x))
= x
+(fold kons knil (unfold-right knull? kar kdr x))
= x
(unfold-right knull? kar kdr (fold-right kons knil x))
= x.
+(unfold-right knull? kar kdr (fold kons knil x))
= x.
take-while
pred clist -> list
+take-while!
pred clist -> list
+
+Take-while!
is the linear-update variant. It is allowed, but not
+required, to alter the argument list to produce the result.
+
+
+(take-while even? '(2 18 3 10 22 9)) => (2 18) ++ + +
drop-while
pred clist -> list
++(drop-while even? '(2 18 3 10 22 9)) => (3 10 22 9) ++The circular-list case may be viewed as "rotating" the list. + + + +
span
pred clist -> [list clist]
+span!
pred list -> [list list]
+break
pred clist -> [list clist]
+break!
pred list -> [list list]
+Span
splits the list into the longest initial prefix whose
+elements all satisfy pred, and the remaining tail.
+Break
inverts the sense of the predicate:
+the tail commences with the first element of the input list
+that satisfies the predicate.
+
+
+In other words:
+span
finds the intial span of elements
+satisfying pred,
+and break
breaks the list at the first element satisfying
+pred.
+
+
+Span
is equivalent to
+
+(values (take-while pred clist) + (drop-while pred clist)) ++ +
+Span!
and break!
are the linear-update variants.
+They are allowed, but not required,
+to alter the argument list to produce the result.
+
+
+(span even? '(2 18 3 10 22 9)) => + (2 18) + (3 10 22 9) + +(break even? '(3 1 4 1 5 9)) => + (3 1) + (4 1 5 9) ++ + diff --git a/scsh/lib/srfi-1.txt b/scsh/lib/srfi-1.txt index 770d148..bdff052 100644 --- a/scsh/lib/srfi-1.txt +++ b/scsh/lib/srfi-1.txt @@ -1,7 +1,7 @@ The SRFI-1 list library -*- outline -*- Olin Shivers 98/10/16 -Last Update: 99/10/2 +Last Update: 99/10/3 Emacs should display this document in outline mode. Say c-h m for instructions on how to move through it by sections (e.g., c-c c-n, c-c c-p). @@ -93,7 +93,7 @@ implementation. I have placed this source on the Net with an unencumbered, - Use of a simple CHECK-ARG procedure for argument checking. - It is written for clarity and well-commented. The current source is - 706 lines of source code and 818 lines of comments and white space. + 768 lines of source code and 826 lines of comments and white space. - It is written for efficiency. Fast paths are provided for common cases. Side-effecting procedures such as FILTER! avoid unnecessary, @@ -137,13 +137,15 @@ Selectors take drop take-right drop-right take! drop-right! + split-at split-at! last last-pair -Miscellaneous: length, append, reverse, zip & count +Miscellaneous: length, append, concatenate, reverse, zip & count # length length+ # append reverse append! reverse! + concatenate concatenate! append-reverse append-reverse! zip unzip1 unzip2 unzip3 unzip4 unzip5 count @@ -157,14 +159,16 @@ Fold, unfold & map Filtering & partitioning filter partition remove - filter! partition! remove! + filter! partition! remove! Searching + member # memq memv - find find-tail + find any every list-index + take-while drop-while take-while! + span break span! break! Deleting delete delete-duplicates @@ -724,6 +728,20 @@ drop-right! flist i -> list (take! (circular-list 1 3 5) 8) => (1 3) (take! (circular-list 1 3 5) 8) => (1 3 5 1 3 5 1 3) +split-at x i -> [list object] +split-at! x i -> [list object] + SPLIT-AT splits the list X at index I, returning a list of the + first I elements, and the remaining tail. It is equivalent + to + (values (take x i) (drop x i)) + + SPLIT-AT! is the linear-update variant. It is allowed, but not + required, to alter the argument list to produce the result. + + (split-at '(a b c d e f g h) 3) => + (a b c) + (d e f g h) + last pair -> object last-pair pair -> pair LAST returns the last element of the non-empty, finite list PAIR. @@ -734,8 +752,8 @@ last-pair pair -> pair (last-pair '(a b c . d)) => (c . d) -** Miscellaneous: length, append, reverse, zip & count -====================================================== +** Miscellaneous: length, append, concatenate, reverse, zip & count +=================================================================== length list -> integer R5RS length+ clist -> integer or #f @@ -779,6 +797,25 @@ append! list1 ... -> value the result list. The last argument is never altered; the result list shares structure with this parameter. +concatenate list-of-lists -> value +concatenate! list-of-lists -> value + These functions append the elements of their argument together. + That is, CONCATENATE returns + (apply append list-of-lists) + or, equivalently, + (reduce-right append '() list-of-lists) + + CONCATENATE! is the linear-update variant, defined in + terms of APPEND! instead of APPEND. + + Note that some Scheme implementations do not support passing more than a + certain number (e.g., 64) of arguments to an n-ary procedure. In these + implementations, the (APPLY APPEND ...) idiom would fail when applied to + long lists, but CONCATENATE would continue to function properly. + + As with APPEND and APPEND!, the last element of the input list + may be any value at all. + reverse list -> list R5RS reverse! list -> list REVERSE returns a newly allocated list consisting of the elements of @@ -979,6 +1016,9 @@ reduce f ridentity list -> value Note: MIT Scheme and Haskell flip F's arg order for their REDUCE and FOLD functions. + ;; Take the max of a list of non-negative integers. + (reduce max 0 nums) ; i.e., (apply max 0 nums) + reduce-right f ridentity list -> value REDUCE-RIGHT is the fold-right variant of REDUCE. It obeys the following definition: @@ -989,8 +1029,63 @@ reduce-right f ridentity list -> value ...in other words, we compute (fold-right F RIDENTITY LIST). + ;; Append a bunch of lists together. + ;; I.e., (apply append list-of-lists) + (reduce-right append '() list-of-lists) -unfold p f g seed [tail] -> value +unfold p f g seed [tail-gen]-> list + UNFOLD is best described by its basic recursion: + (unfold p f g seed) = (if (p seed) (tail-gen seed) + (cons (f seed) + (unfold p f g (g seed)))) + P: Determines when to stop unfolding. + F: Maps each seed value to the corresponding list element. + G: Maps each seed value to next seed value. + SEED: The "state" value for the unfold. + TAIL-GEN: creates the tail of the list; defaults to (lambda (x) '()) + + In other words, we use G to generate a sequence of seed values + SEED, (G SEED), (G^2 SEED), (G^3 SEED), ... + These seed values are mapped to list elements by F, producing the + elements of the result list in a left-to-right order. P says when to stop. + + UNFOLD is the fundamental recursive list constructor, just as FOLD-RIGHT + is the fundamental recursive list consumer. While UNFOLD may seem a + bit abstract to novice functional programmers, it can be used in a number + of ways: + + (unfold (lambda (x) (> x 10)) ; List of squares: 1^2 ... 10^2. + (lambda (x) (* x x)) + (lambda (x) (+ x 1)) + 1) + + (unfold null-list? car cdr lis) ; Copy a proper list. + + ;; Read current input port into a list of values. + (unfold eof-object? values (lambda (x) (read)) (read)) + + ;; Copy a possibly non-proper list: + (unfold not-pair? car cdr lis + values) + + ;; Append HEAD onto TAIL: + (unfold null-list? car cdr head + (lambda (x) tail)) + + Interested functional programmers may enjoy noting that FOLD-RIGHT and + UNFOLD are in some sense inverses. That is, given operations KNULL?, + KAR, KDR, KONS, and KNIL satisfying + (kons (kar x) (kdr x)) = x and (knull? knil) = #t + then + (FOLD-RIGHT kons knil (UNFOLD knull? kar kdr x)) = x + and + (UNFOLD knull? kar kdr (FOLD-RIGHT kons knil x)) = x. + + This combinator sometimes is called an "anamorphism;" when an + explicit TAIL-GEN procedure is supplied, it is called an + "apomorphism." + +unfold-right p f g seed [tail] -> value UNFOLD constructs a list with the following loop: (let lp ((seed seed) (lis tail)) (if (p seed) lis @@ -1003,82 +1098,40 @@ unfold p f g seed [tail] -> value SEED: The "state" value for the unfold. TAIL: list terminator; defaults to '(). - UNFOLD is the fundamental iterative list constructor, just as FOLD is the - fundamental iterative list consumer. While UNFOLD may seem a bit abstract - to novice functional programmers, it can be used in a number of ways: + In other words, we use G to generate a sequence of seed values + SEED, (G SEED), (G^2 SEED), (G^3 SEED), ... + These seed values are mapped to list elements by F, producing the + elements of the result list in a right-to-left order. P says when to stop. - (unfold zero? ; List of squares: 1^2 ... 10^2 - (lambda (x) (* x x)) - (lambda (x) (- x 1)) - 10) - - (unfold null-list? car cdr lis) ; Reverse a proper list. + UNFOLD-RIGHT is the fundamental iterative list constructor, just as FOLD + is the fundamental iterative list consumer. While UNFOLD-RIGHT may seem a + bit abstract to novice functional programmers, it can be used in a number + of ways: - ;; Read current input port into a list of values. - (unfold eof-object? values (lambda (x) (read)) (read)) - - ;; (APPEND-REVERSE rev-head tail) - (unfold null-list? car cdr rev-head tail) - - Interested functional programmers may enjoy noting that FOLD and UNFOLD - are in some sense inverses. That is, given operations KNULL?, KAR, KDR, - KONS, and KNIL satisfying - (kons (kar x) (kdr x)) = x and (knull? knil) = #t - then - (FOLD kons knil (UNFOLD knull? kar kdr x)) = x - and - (UNFOLD knull? kar kdr (FOLD kons knil x)) = x. - - This combinator presumably has some pretentious mathematical name; - interested readers are invited to communicate it to the author. - -unfold-right p f g seed [tail-gen]-> list - UNFOLD-RIGHT is best described by its basic recursion: - (unfold-right p f g seed) = (if (p seed) (tail-gen seed) - (cons (f seed) - (unfold-right p f g (g seed)))) - P: Determines when to stop unfolding. - F: Maps each seed value to the corresponding list element. - G: Maps each seed value to next seed value. - SEED: The "state" value for the unfold. - TAIL-GEN: creates the tail of the list; defaults to (lambda (x) '()) - - UNFOLD-RIGHT is the fundamental recursive list constructor, just as - FOLD-RIGHT is the fundamental recursive list consumer. While UNFOLD-RIGHT - may seem a bit abstract to novice functional programmers, it can be used - in a number of ways: - - (unfold-right (lambda (x) (> x 10)) ; List of squares: 1^2 ... 10^2. + (unfold-right zero? ; List of squares: 1^2 ... 10^2 (lambda (x) (* x x)) - (lambda (x) (+ x 1)) - 1) + (lambda (x) (- x 1)) + 10) - (unfold-right null-list? car cdr lis) ; Copy a proper list. + (unfold-right null-list? car cdr lis) ; Reverse a proper list. ;; Read current input port into a list of values. (unfold-right eof-object? values (lambda (x) (read)) (read)) - ;; Copy a possibly non-proper list: - (unfold-right not-pair? car cdr lis - values) + ;; (APPEND-REVERSE rev-head tail) + (unfold-right null-list? car cdr rev-head tail) - ;; Append HEAD onto TAIL: - (unfold-right null-list? car cdr head - (lambda (x) tail)) - - - Interested functional programmers may enjoy noting that FOLD-RIGHT and + Interested functional programmers may enjoy noting that FOLD and UNFOLD-RIGHT are in some sense inverses. That is, given operations KNULL?, KAR, KDR, KONS, and KNIL satisfying (kons (kar x) (kdr x)) = x and (knull? knil) = #t then - (FOLD-RIGHT kons knil (UNFOLD-RIGHT knull? kar kdr x)) = x + (FOLD kons knil (UNFOLD-RIGHT knull? kar kdr x)) = x and - (UNFOLD-RIGHT knull? kar kdr (FOLD-RIGHT kons knil x)) = x. + (UNFOLD-RIGHT knull? kar kdr (FOLD kons knil x)) = x. - This combinator sometimes is called an "anamorphism;" when an - explicit TAIL-GEN procedure is supplied, it is called an - "apomorphism." + This combinator presumably has some pretentious mathematical name; + interested readers are invited to communicate it to the author. map proc clist1 clist2 ... -> list R5RS+ @@ -1337,6 +1390,55 @@ find-tail pred clist -> pair or false (find-tail (lambda (elt) (equal? x elt)) lis) In the circular-list case, this procedure "rotates" the list. + + FIND-TAIL is essentially DROP-WHILE, where the sense of the predicate + is inverted: FIND-TAIL searches until it finds an element satisfying + the predicate; DROP-WHILE searches until it finds an element that + *doesn't* satisfy the predicate. + +take-while pred clist -> list +take-while! pred clist -> list + Returns the longest initial prefix of CLIST whose elements all + satisfy the predicate PRED. + + TAKE-WHILE! is the linear-update variant. It is allowed, but not + required, to alter the argument list to produce the result. + + (take-while even? '(2 18 3 10 22 9)) => (2 18) + +drop-while pred clist -> list + Drops the longest initial prefix of LIST whose elements all + satisfy the predicate PRED, and returns the rest of the list. + + (drop-while even? '(2 18 3 10 22 9)) => (3 10 22 9) + + The circular-list case may be viewed as "rotating" the list. + +span pred clist -> [list clist] +span! pred list -> [list list] +break pred clist -> [list clist] +break! pred list -> [list list] + SPAN splits the list into the longest initial prefix whose elements + all satisfy PRED, and the remaining tail. BREAK inverts the sense + of the predicate: the tail commences with the first element of the + input list that satisfies the predicate. + + In other words: SPAN finds the intial span of elements satisfying + PRED, and BREAK breaks the list at the first element satisfying PRED. + + SPAN is equivalent to (VALUES (TAKE-WHILE PRED CLIST) + (DROP-WHILE PRED CLIST)). + + SPAN! and BREAK! are the linear-update variants. They are allowed, but not + required, to alter the argument list to produce the result. + + (span even? '(2 18 3 10 22 9)) => + (2 18) + (3 10 22 9) + + (break even? '(3 1 4 1 5 9)) => + (3 1) + (4 1 5 9) any pred clist1 clist2 ... -> value Applies the predicate across the lists, returning true if the predicate