Updated list library to most recent revision of the SRFI. Olin
This commit is contained in:
parent
dbf3e322eb
commit
19995a158c
|
@ -26,15 +26,19 @@
|
||||||
;;; take drop
|
;;; take drop
|
||||||
;;; take-right drop-right
|
;;; take-right drop-right
|
||||||
;;; take! drop-right!
|
;;; take! drop-right!
|
||||||
|
;;; split-at split-at!
|
||||||
;;; last last-pair
|
;;; last last-pair
|
||||||
;;; zip unzip1 unzip2 unzip3 unzip4 unzip5
|
;;; zip unzip1 unzip2 unzip3 unzip4 unzip5
|
||||||
;;; count
|
;;; count
|
||||||
;;; append! append-reverse append-reverse!
|
;;; append! append-reverse append-reverse! concatenate concatenate!
|
||||||
;;; unfold fold fold-right pair-fold pair-fold-right reduce reduce-right
|
;;; 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
|
;;; 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
|
;;; find find-tail any every list-index
|
||||||
|
;;; take-while drop-while take-while!
|
||||||
|
;;; span break span! break!
|
||||||
;;; delete delete!
|
;;; delete delete!
|
||||||
;;; alist-cons alist-copy
|
;;; alist-cons alist-copy
|
||||||
;;; delete-duplicates delete-duplicates!
|
;;; delete-duplicates delete-duplicates!
|
||||||
|
@ -246,7 +250,7 @@
|
||||||
;;; (cons* a1 a2 ... an) = (cons a1 (cons a2 (cons ... an)))
|
;;; (cons* a1 a2 ... an) = (cons a1 (cons a2 (cons ... an)))
|
||||||
;;; (cons* a1) = a1 (cons* a1 a2 ...) = (cons a1 (cons* a2 ...))
|
;;; (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)
|
(define (cons* first . rest)
|
||||||
(let recur ((x first) (rest rest))
|
(let recur ((x first) (rest rest))
|
||||||
|
@ -254,7 +258,7 @@
|
||||||
(cons x (recur (car rest) (cdr rest)))
|
(cons x (recur (car rest) (cdr rest)))
|
||||||
x)))
|
x)))
|
||||||
|
|
||||||
;;; (unfold-right not-pair? car cdr lis values)
|
;;; (unfold not-pair? car cdr lis values)
|
||||||
|
|
||||||
(define (list-copy lis)
|
(define (list-copy lis)
|
||||||
(let recur ((lis lis))
|
(let recur ((lis lis))
|
||||||
|
@ -571,6 +575,21 @@
|
||||||
; lis)))
|
; lis)))
|
||||||
; (list-tail lis k)))
|
; (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)))
|
(define (last lis) (car (last-pair lis)))
|
||||||
|
|
||||||
|
@ -625,8 +644,8 @@
|
||||||
(cons (car (cddddr elt)) e)))))))
|
(cons (car (cddddr elt)) e)))))))
|
||||||
|
|
||||||
|
|
||||||
;;; append! append-reverse append-reverse!
|
;;; append! append-reverse append-reverse! concatenate concatenate!
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
(define (append! . lists)
|
(define (append! . lists)
|
||||||
;; First, scan through lists looking for a non-empty one.
|
;; First, scan through lists looking for a non-empty one.
|
||||||
|
@ -679,6 +698,8 @@
|
||||||
(lp next-rev rev-head)))))
|
(lp next-rev rev-head)))))
|
||||||
|
|
||||||
|
|
||||||
|
(define (concatenate lists) (reduce-right append '() lists))
|
||||||
|
(define (concatenate! lists) (reduce-right append! '() lists))
|
||||||
|
|
||||||
;;; Fold/map internal utilities
|
;;; Fold/map internal utilities
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
@ -778,25 +799,25 @@
|
||||||
;;; fold/unfold
|
;;; fold/unfold
|
||||||
;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
(define (unfold p f g seed . maybe-tail)
|
(define (unfold-right p f g seed . maybe-tail)
|
||||||
(check-arg procedure? p unfold)
|
(check-arg procedure? p unfold-right)
|
||||||
(check-arg procedure? f unfold)
|
(check-arg procedure? f unfold-right)
|
||||||
(check-arg procedure? g unfold)
|
(check-arg procedure? g unfold-right)
|
||||||
(let lp ((seed seed) (ans (:optional maybe-tail '())))
|
(let lp ((seed seed) (ans (:optional maybe-tail '())))
|
||||||
(if (p seed) ans
|
(if (p seed) ans
|
||||||
(lp (g seed)
|
(lp (g seed)
|
||||||
(cons (f seed) ans)))))
|
(cons (f seed) ans)))))
|
||||||
|
|
||||||
|
|
||||||
(define (unfold-right p f g seed . maybe-tail-gen)
|
(define (unfold p f g seed . maybe-tail-gen)
|
||||||
(check-arg procedure? p unfold-right)
|
(check-arg procedure? p unfold)
|
||||||
(check-arg procedure? f unfold-right)
|
(check-arg procedure? f unfold)
|
||||||
(check-arg procedure? g unfold-right)
|
(check-arg procedure? g unfold)
|
||||||
(if (pair? maybe-tail-gen)
|
(if (pair? maybe-tail-gen)
|
||||||
|
|
||||||
(let ((tail-gen (car maybe-tail-gen)))
|
(let ((tail-gen (car maybe-tail-gen)))
|
||||||
(if (pair? (cdr 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))
|
(let recur ((seed seed))
|
||||||
(if (p seed) (tail-gen seed)
|
(if (p seed) (tail-gen seed)
|
||||||
|
@ -1252,11 +1273,8 @@
|
||||||
(filter! (lambda (elt) (not (= key (car elt)))) alist)))
|
(filter! (lambda (elt) (not (= key (car elt)))) alist)))
|
||||||
|
|
||||||
|
|
||||||
;;; find find-tail any every list-index
|
;;; find find-tail take-while drop-while span break any every list-index
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
;;; ANY returns the first true value produced by PRED.
|
|
||||||
;;; FIND returns the first list elt passed by PRED.
|
|
||||||
|
|
||||||
(define (find pred list)
|
(define (find pred list)
|
||||||
(cond ((find-tail pred list) => car)
|
(cond ((find-tail pred list) => car)
|
||||||
|
@ -1269,6 +1287,58 @@
|
||||||
(if (pred (car list)) list
|
(if (pred (car list)) list
|
||||||
(lp (cdr 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)
|
(define (any pred lis1 . lists)
|
||||||
(check-arg procedure? pred any)
|
(check-arg procedure? pred any)
|
||||||
(if (pair? lists)
|
(if (pair? lists)
|
||||||
|
@ -1315,8 +1385,6 @@
|
||||||
(if (null-list? tail)
|
(if (null-list? tail)
|
||||||
(pred head) ; Last PRED app is tail call.
|
(pred head) ; Last PRED app is tail call.
|
||||||
(and (pred head) (lp (car tail) (cdr tail))))))))
|
(and (pred head) (lp (car tail) (cdr tail))))))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(define (list-index pred lis1 . lists)
|
(define (list-index pred lis1 . lists)
|
||||||
(check-arg procedure? pred list-index)
|
(check-arg procedure? pred list-index)
|
||||||
|
|
|
@ -13,17 +13,21 @@
|
||||||
;;; take drop
|
;;; take drop
|
||||||
;;; take-right drop-right
|
;;; take-right drop-right
|
||||||
;;; take! drop-right!
|
;;; take! drop-right!
|
||||||
|
;;; take-while drop-while take-while!
|
||||||
|
;;; split-at split-at!
|
||||||
|
;;; span break
|
||||||
|
;;; span! break!
|
||||||
;;; last last-pair
|
;;; last last-pair
|
||||||
;;; length+
|
;;; length+
|
||||||
;;; append! reverse! append-reverse append-reverse!
|
;;; append! reverse! append-reverse append-reverse! concatenate concatenate!
|
||||||
;;; zip unzip1 unzip2 unzip3 unzip4 unzip5
|
;;; zip unzip1 unzip2 unzip3 unzip4 unzip5
|
||||||
;;; count
|
;;; count
|
||||||
;;; unfold unfold-right
|
;;; unfold unfold-right
|
||||||
;;; fold unfold pair-fold reduce
|
;;; fold unfold pair-fold reduce
|
||||||
;;; fold-right unfold-right pair-fold-right reduce-right
|
;;; fold-right unfold-right pair-fold-right reduce-right
|
||||||
;;; append-map append-map! map! pair-for-each filter-map map-in-order
|
;;; 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
|
;;; find find-tail any every list-index
|
||||||
;;; delete delete! delete-duplicates delete-duplicates!
|
;;; delete delete! delete-duplicates delete-duplicates!
|
||||||
;;; alist-cons alist-copy
|
;;; alist-cons alist-copy
|
||||||
|
@ -87,6 +91,9 @@
|
||||||
((take drop take-right drop-right take! drop-right!)
|
((take drop take-right drop-right take! drop-right!)
|
||||||
(proc (:value :exact-integer) :value))
|
(proc (:value :exact-integer) :value))
|
||||||
|
|
||||||
|
((split-at split-at!)
|
||||||
|
(proc (:value :exact-integer) (some-values :value :value)))
|
||||||
|
|
||||||
(last (proc (:pair) :value))
|
(last (proc (:pair) :value))
|
||||||
(last-pair (proc (:pair) :pair))
|
(last-pair (proc (:pair) :pair))
|
||||||
|
|
||||||
|
@ -94,6 +101,7 @@
|
||||||
(append! (proc (:value &rest :value) :value))
|
(append! (proc (:value &rest :value) :value))
|
||||||
(reverse! (proc (:value) :value))
|
(reverse! (proc (:value) :value))
|
||||||
((append-reverse append-reverse!) (proc (:value :value) :value))
|
((append-reverse append-reverse!) (proc (:value :value) :value))
|
||||||
|
((concatenate concatenate!) (proc (:value) :value))
|
||||||
|
|
||||||
(zip (proc (:value &rest :value) :value))
|
(zip (proc (:value &rest :value) :value))
|
||||||
(unzip1 (proc (:value) :value))
|
(unzip1 (proc (:value) :value))
|
||||||
|
@ -138,6 +146,12 @@
|
||||||
|
|
||||||
((find find-tail) (proc ((proc (:value) :boolean) :value) :value))
|
((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)
|
((any every)
|
||||||
(proc ((proc (:value &rest :value) :value) :value &rest :value) :value))
|
(proc ((proc (:value &rest :value) :value) :value &rest :value) :value))
|
||||||
|
|
||||||
|
|
|
@ -253,7 +253,7 @@ implementation. I have placed this source on the Net with an unencumbered,
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<li>It is written for clarity and well-commented. The current source is
|
<li>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.
|
||||||
|
|
||||||
<li>It is written for efficiency. Fast paths are provided for common
|
<li>It is written for efficiency. Fast paths are provided for common
|
||||||
cases. Side-effecting procedures such as <code>filter!</code> avoid unnecessary,
|
cases. Side-effecting procedures such as <code>filter!</code> avoid unnecessary,
|
||||||
|
@ -310,15 +310,16 @@ extended <a href="#R5RS">R5RS</a></abbr>
|
||||||
<a href="#take">take</a> <a href="#drop">drop</a>
|
<a href="#take">take</a> <a href="#drop">drop</a>
|
||||||
<a href="#take-right">take-right</a> <a href="#drop-right">drop-right</a>
|
<a href="#take-right">take-right</a> <a href="#drop-right">drop-right</a>
|
||||||
<a href="#take!">take!</a> <a href="#drop-right!">drop-right!</a>
|
<a href="#take!">take!</a> <a href="#drop-right!">drop-right!</a>
|
||||||
|
<a href="#split-at">split-at</a> <a href="#split-at!">split-at!</a>
|
||||||
<a href="#last">last</a> <a href="#last-pair">last-pair</a>
|
<a href="#last">last</a> <a href="#last-pair">last-pair</a>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<dt class=proc-index> Miscellaneous: length, append, reverse, zip & count
|
<dt class=proc-index> Miscellaneous: length, append, concatenate, reverse, zip & count
|
||||||
<dd class=proc-index>
|
<dd class=proc-index>
|
||||||
<pre class=proc-index>
|
<pre class=proc-index>
|
||||||
<span class=r5rs-proc><a href="#length">length</a></span> <a href="#length+">length+</a>
|
<span class=r5rs-proc><a href="#length">length</a></span> <a href="#length+">length+</a>
|
||||||
<span class=r5rs-proc><a href="#append">append</a> <a href="#reverse">reverse</a></span>
|
<span class=r5rs-proc><a href="#append">append</a></span> <a href="#concatenate">concatenate</a> <span class=r5rs-proc><a href="#reverse">reverse</a></span>
|
||||||
<a href="#append!">append!</a> <a href="#reverse!">reverse!</a>
|
<a href="#append!">append!</a> <a href="#concatenate!">concatenate!</a> <a href="#reverse!">reverse!</a>
|
||||||
<a href="#append-reverse">append-reverse</a> <a href="#append-reverse!">append-reverse!</a>
|
<a href="#append-reverse">append-reverse</a> <a href="#append-reverse!">append-reverse!</a>
|
||||||
<a href="#zip">zip</a> <a href="#unzip1">unzip1</a> <a href="#unzip2">unzip2</a> <a href="#unzip3">unzip3</a> <a href="#unzip4">unzip4</a> <a href="#unzip5">unzip5</a>
|
<a href="#zip">zip</a> <a href="#unzip1">unzip1</a> <a href="#unzip2">unzip2</a> <a href="#unzip3">unzip3</a> <a href="#unzip4">unzip4</a> <a href="#unzip5">unzip5</a>
|
||||||
<a href="#count">count</a>
|
<a href="#count">count</a>
|
||||||
|
@ -348,6 +349,8 @@ extended <a href="#R5RS">R5RS</a></abbr>
|
||||||
<a href="#find">find</a> <a href="#find-tail">find-tail</a>
|
<a href="#find">find</a> <a href="#find-tail">find-tail</a>
|
||||||
<a href="#any">any</a> <a href="#every">every</a>
|
<a href="#any">any</a> <a href="#every">every</a>
|
||||||
<a href="#list-index">list-index</a>
|
<a href="#list-index">list-index</a>
|
||||||
|
<a href="#take-while">take-while</a> <a href="#drop-while">drop-while</a> <a href="#take-while!">take-while!</a>
|
||||||
|
<a href="#span">span</a> <a href="#break">break</a> <a href="#span!">span!</a> <a href="#break!">break!</a>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<dt class=proc-index> Deleting
|
<dt class=proc-index> Deleting
|
||||||
|
@ -563,10 +566,11 @@ operators, so we don't want to exclude these possible implementations.
|
||||||
<p>
|
<p>
|
||||||
The linear-update procedures in this library are
|
The linear-update procedures in this library are
|
||||||
<div class=indent><code>
|
<div class=indent><code>
|
||||||
take! drop-right!
|
take! drop-right! split-at!
|
||||||
append! reverse! append-reverse!
|
append! concatenate! reverse! append-reverse!
|
||||||
append-map! map!
|
append-map! map!
|
||||||
filter! partition! remove!
|
filter! partition! remove!
|
||||||
|
take-while! span! break!
|
||||||
delete! alist-delete! delete-duplicates!
|
delete! alist-delete! delete-duplicates!
|
||||||
lset-adjoin! lset-union! lset-intersection!
|
lset-adjoin! lset-union! lset-intersection!
|
||||||
lset-difference! lset-xor! lset-diff+intersection!
|
lset-difference! lset-xor! lset-diff+intersection!
|
||||||
|
@ -1242,6 +1246,33 @@ partition the entire universe of Scheme values.
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
==== split-at!
|
||||||
|
==== split-at
|
||||||
|
============================================================================-->
|
||||||
|
<dt class=proc-def1>
|
||||||
|
<a name="split-at"></a>
|
||||||
|
<code class=proc-def>split-at </code><var> x i -> [list object]</var>
|
||||||
|
<dt class=proc-defn>
|
||||||
|
<a name="split-at!"></a>
|
||||||
|
<code class=proc-def>split-at!</code><var> x i -> [list object]</var>
|
||||||
|
<dd class=proc-def>
|
||||||
|
<code>split-at</code> splits the list <var>x</var>
|
||||||
|
at index <var>i</var>, returning a list of the
|
||||||
|
first <var>i</var> elements, and the remaining tail. It is equivalent
|
||||||
|
to
|
||||||
|
<pre class=code-example>
|
||||||
|
(values (take x i) (drop x i))
|
||||||
|
</pre>
|
||||||
|
<code>split-at!</code> is the linear-update variant. It is allowed, but not
|
||||||
|
required, to alter the argument list to produce the result.
|
||||||
|
<pre class=code-example>
|
||||||
|
(split-at '(a b c d e f g h) 3) =>
|
||||||
|
(a b c)
|
||||||
|
(d e f g h)
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
==== last-pair
|
==== last-pair
|
||||||
==== last
|
==== last
|
||||||
|
@ -1266,7 +1297,7 @@ partition the entire universe of Scheme values.
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<!--========================================================================-->
|
<!--========================================================================-->
|
||||||
<h2><a name="Miscellaneous">Miscellaneous: length, append, reverse, zip & count</a></h2>
|
<h2><a name="Miscellaneous">Miscellaneous: length, append, concatenate, reverse, zip & count</a></h2>
|
||||||
|
|
||||||
<dl>
|
<dl>
|
||||||
<!--
|
<!--
|
||||||
|
@ -1330,6 +1361,40 @@ partition the entire universe of Scheme values.
|
||||||
The last argument is never altered; the result
|
The last argument is never altered; the result
|
||||||
list shares structure with this parameter.
|
list shares structure with this parameter.
|
||||||
|
|
||||||
|
<!--
|
||||||
|
==== concatenate concatenate!
|
||||||
|
============================================================================-->
|
||||||
|
<dt class=proc-def1>
|
||||||
|
<a name="concatenate"></a>
|
||||||
|
<code class=proc-def>concatenate </code><var> list-of-lists -> value</var>
|
||||||
|
<dt class=proc-defn>
|
||||||
|
<a name="concatenate!"></a>
|
||||||
|
<code class=proc-def>concatenate!</code><var> list-of-lists -> value</var>
|
||||||
|
<dd class=proc-def>
|
||||||
|
These functions append the elements of their argument together.
|
||||||
|
That is, <code>concatenate</code> returns
|
||||||
|
<pre class=code-example>
|
||||||
|
(apply append list-of-lists)
|
||||||
|
</pre>
|
||||||
|
or, equivalently,
|
||||||
|
<pre class=code-example>
|
||||||
|
(reduce-right append '() list-of-lists)
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<code>concatenate!</code> is the linear-update variant, defined in
|
||||||
|
terms of <code>append!</code> instead of <code>append</code>.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Note that some Scheme implementations do not support passing more than a
|
||||||
|
certain number (<em>e.g.</em>, 64) of arguments to an n-ary procedure.
|
||||||
|
In these implementations, the <code>(apply append ...)</code> idiom
|
||||||
|
would fail when applied to long lists,
|
||||||
|
but <code>concatenate</code> would continue to function properly.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
As with <code>append</code> and <code>append!</code>,
|
||||||
|
the last element of the input list may be any value at all.
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
==== reverse reverse!
|
==== reverse reverse!
|
||||||
============================================================================-->
|
============================================================================-->
|
||||||
|
@ -1643,6 +1708,11 @@ Otherwise, return <code>(fold <var>f</var> (car <var>list</var>) (cdr <var>li
|
||||||
Note: MIT Scheme and Haskell flip F's arg order for their <code>reduce</code> and
|
Note: MIT Scheme and Haskell flip F's arg order for their <code>reduce</code> and
|
||||||
<code>fold</code> functions.
|
<code>fold</code> functions.
|
||||||
|
|
||||||
|
<pre class=code-example>
|
||||||
|
;; Take the max of a list of non-negative integers.
|
||||||
|
(reduce max 0 nums) ; i.e., (apply max 0 nums)
|
||||||
|
</pre>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
==== reduce-right
|
==== reduce-right
|
||||||
============================================================================-->
|
============================================================================-->
|
||||||
|
@ -1661,14 +1731,103 @@ Otherwise, return <code>(fold <var>f</var> (car <var>list</var>) (cdr <var>li
|
||||||
...in other words, we compute
|
...in other words, we compute
|
||||||
<code>(fold-right <var>f</var> <var>ridentity</var> <var>list</var>)</code>.
|
<code>(fold-right <var>f</var> <var>ridentity</var> <var>list</var>)</code>.
|
||||||
|
|
||||||
|
<pre class=code-example>
|
||||||
|
;; Append a bunch of lists together.
|
||||||
|
;; I.e., (apply append list-of-lists)
|
||||||
|
(reduce-right append '() list-of-lists)
|
||||||
|
</pre>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
==== unfold
|
==== unfold
|
||||||
============================================================================-->
|
============================================================================-->
|
||||||
<dt class=proc-def>
|
<dt class=proc-def>
|
||||||
<a name="unfold"></a>
|
<a name="unfold"></a>
|
||||||
<code class=proc-def>unfold</code><var> p f g seed [tail] -> list</var>
|
<code class=proc-def>unfold</code><var> p f g seed [tail-gen] -> list</var>
|
||||||
<dd class=proc-def>
|
<dd class=proc-def>
|
||||||
<code>unfold</code> constructs a list with the following loop:
|
<code>unfold</code> is best described by its basic recursion:
|
||||||
|
<pre class=code-example>
|
||||||
|
(unfold <var>p</var> <var>f</var> <var>g</var> <var>seed</var>) =
|
||||||
|
(if (<var>p</var> <var>seed</var>) (<var>tail-gen</var> <var>seed</var>)
|
||||||
|
(cons (<var>f</var> <var>seed</var>)
|
||||||
|
(unfold <var>p</var> <var>f</var> <var>g</var> (<var>g</var> <var>seed</var>))))
|
||||||
|
</pre>
|
||||||
|
<dl>
|
||||||
|
<dt> <var>p</var> <dd> Determines when to stop unfolding.
|
||||||
|
<dt> <var>f</var> <dd> Maps each seed value to the corresponding list element.
|
||||||
|
<dt> <var>g</var> <dd> Maps each seed value to next seed value.
|
||||||
|
<dt> <var>seed</var> <dd> The "state" value for the unfold.
|
||||||
|
<dt> <var>tail-gen</var> <dd> Creates the tail of the list;
|
||||||
|
defaults to <code>(lambda (x) '())</code>
|
||||||
|
</dl>
|
||||||
|
<p>
|
||||||
|
In other words, we use <var>g</var> to generate a sequence of seed values
|
||||||
|
<div class=indent>
|
||||||
|
<var>seed</var>, <var>g</var>(<var>seed</var>), <var>g<sup>2</sup></var>(<var>seed</var>), <var>g<sup>3</sup></var>(<var>seed</var>), ...
|
||||||
|
</div>
|
||||||
|
These seed values are mapped to list elements by <var>f</var>,
|
||||||
|
producing the elements of the result list in a left-to-right order.
|
||||||
|
<var>P</var> says when to stop.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<code>unfold</code> is the fundamental recursive list constructor,
|
||||||
|
just as <code>fold-right</code> is
|
||||||
|
the fundamental recursive list consumer.
|
||||||
|
While <code>unfold</code> may seem a bit abstract
|
||||||
|
to novice functional programmers, it can be used in a number of ways:
|
||||||
|
|
||||||
|
<pre class=code-example>
|
||||||
|
;; 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))
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
Interested functional programmers may enjoy noting that
|
||||||
|
<code>fold-right</code> and <code>unfold</code>
|
||||||
|
are in some sense inverses.
|
||||||
|
That is, given operations <var>knull?</var>, <var>kar</var>,
|
||||||
|
<var>kdr</var>, <var>kons</var>, and <var>knil</var> satisfying
|
||||||
|
<div class=indent>
|
||||||
|
<code>(<var>kons</var> (<var>kar</var> <var>x</var>) (<var>kdr</var> <var>x</var>))</code> = <code>x</code>
|
||||||
|
and
|
||||||
|
<code>(<var>knull?</var> <var>knil</var>)</code> = <code>#t</code>
|
||||||
|
</div>
|
||||||
|
then
|
||||||
|
<div class=indent>
|
||||||
|
<code>(fold-right <var>kons</var> <var>knil</var> (unfold <var>knull?</var> <var>kar</var> <var>kdr</var> <var>x</var>))</code> = <var>x</var>
|
||||||
|
</div>
|
||||||
|
and
|
||||||
|
<div class=indent>
|
||||||
|
<code>(unfold <var>knull?</var> <var>kar</var> <var>kdr</var> (fold-right <var>kons</var> <var>knil</var> <var>x</var>))</code> = <var>x</var>.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
This combinator sometimes is called an "anamorphism;" when an
|
||||||
|
explicit <var>tail-gen</var> procedure is supplied, it is called an
|
||||||
|
"apomorphism."
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
==== unfold-right
|
||||||
|
============================================================================-->
|
||||||
|
<dt class=proc-def>
|
||||||
|
<a name="unfold-right"></a>
|
||||||
|
<code class=proc-def>unfold-right</code><var> p f g seed [tail] -> list</var>
|
||||||
|
<dd class=proc-def>
|
||||||
|
<code>unfold-right</code> constructs a list with the following loop:
|
||||||
<pre class=code-example>
|
<pre class=code-example>
|
||||||
(let lp ((seed seed) (lis tail))
|
(let lp ((seed seed) (lis tail))
|
||||||
(if (p seed) lis
|
(if (p seed) lis
|
||||||
|
@ -1683,103 +1842,39 @@ Otherwise, return <code>(fold <var>f</var> (car <var>list</var>) (cdr <var>li
|
||||||
<dt> <var>tail</var> <dd> list terminator; defaults to <code>'()</code>.
|
<dt> <var>tail</var> <dd> list terminator; defaults to <code>'()</code>.
|
||||||
</dl>
|
</dl>
|
||||||
<p>
|
<p>
|
||||||
<code>unfold</code> is the fundamental iterative list constructor,
|
In other words, we use <var>g</var> to generate a sequence of seed values
|
||||||
|
<div class=indent>
|
||||||
|
<var>seed</var>, <var>g</var>(<var>seed</var>), <var>g<sup>2</sup></var>(<var>seed</var>), <var>g<sup>3</sup></var>(<var>seed</var>), ...
|
||||||
|
</div>
|
||||||
|
These seed values are mapped to list elements by <var>f</var>,
|
||||||
|
producing the elements of the result list in a right-to-left order.
|
||||||
|
<var>P</var> says when to stop.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<code>unfold-right</code> is the fundamental iterative list constructor,
|
||||||
just as <code>fold</code> is the
|
just as <code>fold</code> is the
|
||||||
fundamental iterative list consumer.
|
fundamental iterative list consumer.
|
||||||
While <code>unfold</code> may seem a bit abstract
|
|
||||||
to novice functional programmers, it can be used in a number of ways:
|
|
||||||
<pre class=code-example>
|
|
||||||
;; 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)
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
Interested functional programmers may enjoy noting that
|
|
||||||
<code>fold</code> and <code>unfold</code>
|
|
||||||
are in some sense inverses.
|
|
||||||
That is, given operations <var>knull?</var>, <var>kar</var>,
|
|
||||||
<var>kdr</var>, <var>kons</var>, and <var>knil</var> satisfying
|
|
||||||
<div class=indent>
|
|
||||||
<code>(<var>kons</var> (<var>kar</var> <var>x</var>) (<var>kdr</var> <var>x</var>))</code> = <code>x</code>
|
|
||||||
and
|
|
||||||
<code>(<var>knull?</var> <var>knil</var>)</code> = <code>#t</code>
|
|
||||||
</div>
|
|
||||||
then
|
|
||||||
<div class=indent>
|
|
||||||
<code>(fold <var>kons</var> <var>knil</var> (unfold <var>knull?</var> <var>kar</var> <var>kdr</var> <var>x</var>))</code> = <var>x</var>
|
|
||||||
</div>
|
|
||||||
and
|
|
||||||
<div class=indent>
|
|
||||||
<code>(unfold <var>knull?</var> <var>kar</var> <var>kdr</var> (fold <var>kons</var> <var>knil</var> <var>x</var>))</code> = <var>x</var>.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
This combinator presumably has some pretentious mathematical name;
|
|
||||||
interested readers are invited to communicate it to the author.
|
|
||||||
|
|
||||||
|
|
||||||
<!--
|
|
||||||
==== unfold-right
|
|
||||||
============================================================================-->
|
|
||||||
<dt class=proc-def>
|
|
||||||
<a name="unfold-right"></a>
|
|
||||||
<code class=proc-def>unfold-right</code><var> p f g seed [tail-gen] -> list</var>
|
|
||||||
<dd class=proc-def>
|
|
||||||
<code>unfold</code> is best described by its basic recursion:
|
|
||||||
<pre class=code-example>
|
|
||||||
(unfold-right <var>p</var> <var>f</var> <var>g</var> <var>seed</var>) =
|
|
||||||
(if (<var>p</var> <var>seed</var>) (<var>tail-gen</var> <var>seed</var>)
|
|
||||||
(cons (<var>f</var> <var>seed</var>)
|
|
||||||
(unfold-right <var>p</var> <var>f</var> <var>g</var> (<var>g</var> <var>seed</var>))))
|
|
||||||
</pre>
|
|
||||||
<dl>
|
|
||||||
<dt> <var>p</var> <dd> Determines when to stop unfolding.
|
|
||||||
<dt> <var>f</var> <dd> Maps each seed value to the corresponding list element.
|
|
||||||
<dt> <var>g</var> <dd> Maps each seed value to next seed value.
|
|
||||||
<dt> <var>seed</var> <dd> The "state" value for the unfold.
|
|
||||||
<dt> <var>tail-gen</var> <dd> Creates the tail of the list;
|
|
||||||
defaults to <code>(lambda (x) '())</code>
|
|
||||||
</dl>
|
|
||||||
<p>
|
|
||||||
<code>unfold-right</code> is the fundamental recursive list constructor,
|
|
||||||
just as <code>fold-right</code> is
|
|
||||||
the fundamental recursive list consumer.
|
|
||||||
While <code>unfold-right</code> may seem a bit abstract
|
While <code>unfold-right</code> may seem a bit abstract
|
||||||
to novice functional programmers, it can be used in a number of ways:
|
to novice functional programmers, it can be used in a number of ways:
|
||||||
|
|
||||||
<pre class=code-example>
|
<pre class=code-example>
|
||||||
;; List of squares: 1^2 ... 10^2
|
;; List of squares: 1^2 ... 10^2
|
||||||
(unfold-right (lambda (x) (> x 10))
|
(unfold-right zero?
|
||||||
(lambda (x) (* x x))
|
(lambda (x) (* x x))
|
||||||
(lambda (x) (+ x 1))
|
(lambda (x) (- x 1))
|
||||||
1)
|
10)
|
||||||
|
|
||||||
(unfold-right null-list? car cdr lis) ; Copy a proper list.
|
;; Reverse a proper list.
|
||||||
|
(unfold-right null-list? car cdr lis)
|
||||||
|
|
||||||
;; Read current input port into a list of values.
|
;; Read current input port into a list of values.
|
||||||
(unfold-right eof-object? values (lambda (x) (read)) (read))
|
(unfold-right eof-object? values (lambda (x) (read)) (read))
|
||||||
|
|
||||||
;; Copy a possibly non-proper list:
|
;; (append-reverse rev-head tail)
|
||||||
(unfold-right not-pair? car cdr lis
|
(unfold-right null-list? car cdr rev-head tail)
|
||||||
values)
|
|
||||||
|
|
||||||
;; Append HEAD onto TAIL:
|
|
||||||
(unfold-right null-list? car cdr head
|
|
||||||
(lambda (x) tail))
|
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
Interested functional programmers may enjoy noting that
|
Interested functional programmers may enjoy noting that
|
||||||
<code>fold-right</code> and <code>unfold-right</code>
|
<code>fold</code> and <code>unfold-right</code>
|
||||||
are in some sense inverses.
|
are in some sense inverses.
|
||||||
That is, given operations <var>knull?</var>, <var>kar</var>,
|
That is, given operations <var>knull?</var>, <var>kar</var>,
|
||||||
<var>kdr</var>, <var>kons</var>, and <var>knil</var> satisfying
|
<var>kdr</var>, <var>kons</var>, and <var>knil</var> satisfying
|
||||||
|
@ -1790,17 +1885,15 @@ Otherwise, return <code>(fold <var>f</var> (car <var>list</var>) (cdr <var>li
|
||||||
</div>
|
</div>
|
||||||
then
|
then
|
||||||
<div class=indent>
|
<div class=indent>
|
||||||
<code>(fold-right <var>kons</var> <var>knil</var> (unfold-right <var>knull?</var> <var>kar</var> <var>kdr</var> <var>x</var>))</code> = <var>x</var>
|
<code>(fold <var>kons</var> <var>knil</var> (unfold-right <var>knull?</var> <var>kar</var> <var>kdr</var> <var>x</var>))</code> = <var>x</var>
|
||||||
</div>
|
</div>
|
||||||
and
|
and
|
||||||
<div class=indent>
|
<div class=indent>
|
||||||
<code>(unfold-right <var>knull?</var> <var>kar</var> <var>kdr</var> (fold-right <var>kons</var> <var>knil</var> <var>x</var>))</code> = <var>x</var>.
|
<code>(unfold-right <var>knull?</var> <var>kar</var> <var>kdr</var> (fold <var>kons</var> <var>knil</var> <var>x</var>))</code> = <var>x</var>.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
This combinator sometimes is called an "anamorphism;" when an
|
This combinator presumably has some pretentious mathematical name;
|
||||||
explicit <var>tail-gen</var> procedure is supplied, it is called an
|
interested readers are invited to communicate it to the author.
|
||||||
"apomorphism."
|
|
||||||
|
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
==== map
|
==== map
|
||||||
|
@ -2194,6 +2287,104 @@ representatives:
|
||||||
|
|
||||||
In the circular-list case, this procedure "rotates" the list.
|
In the circular-list case, this procedure "rotates" the list.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<code>Find-tail</code> is essentially <code>drop-while</code>,
|
||||||
|
where the sense of the predicate is inverted:
|
||||||
|
<code>Find-tail</code> searches until it finds an element satisfying
|
||||||
|
the predicate; <code>drop-while</code> searches until it finds an
|
||||||
|
element that <em>doesn't</em> satisfy the predicate.
|
||||||
|
|
||||||
|
<!--
|
||||||
|
==== take-while take-while!
|
||||||
|
============================================================================-->
|
||||||
|
<dt class=proc-def1>
|
||||||
|
<a name="take-while"></a>
|
||||||
|
<code class=proc-def>take-while </code><var> pred clist -> list</var>
|
||||||
|
<dt class=proc-defn>
|
||||||
|
<a name="take-while!"></a>
|
||||||
|
<code class=proc-def>take-while!</code><var> pred clist -> list</var>
|
||||||
|
<dd class=proc-def>
|
||||||
|
|
||||||
|
Returns the longest initial prefix of <var>clist</var> whose elements all
|
||||||
|
satisfy the predicate <var>pred</var>.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<code>Take-while!</code> is the linear-update variant. It is allowed, but not
|
||||||
|
required, to alter the argument list to produce the result.
|
||||||
|
|
||||||
|
<pre class=code-example>
|
||||||
|
(take-while even? '(2 18 3 10 22 9)) => (2 18)
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
==== drop-while
|
||||||
|
============================================================================-->
|
||||||
|
<dt class=proc-def>
|
||||||
|
<a name="drop-while"></a>
|
||||||
|
<code class=proc-def>drop-while</code><var> pred clist -> list</var>
|
||||||
|
<dd class=proc-def>
|
||||||
|
Drops the longest initial prefix of <var>clist</var> whose elements all
|
||||||
|
satisfy the predicate <var>pred</var>, and returns the rest of the list.
|
||||||
|
|
||||||
|
<pre class=code-example>
|
||||||
|
(drop-while even? '(2 18 3 10 22 9)) => (3 10 22 9)
|
||||||
|
</pre>
|
||||||
|
The circular-list case may be viewed as "rotating" the list.
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
==== span span! break break!
|
||||||
|
============================================================================-->
|
||||||
|
<dt class=proc-def1>
|
||||||
|
<a name="span"></a>
|
||||||
|
<code class=proc-def>span </code><var> pred clist -> [list clist]</var>
|
||||||
|
<dt class=proc-defi>
|
||||||
|
<a name="span!"></a>
|
||||||
|
<code class=proc-def>span! </code><var> pred list -> [list list]</var>
|
||||||
|
<dt class=proc-defi>
|
||||||
|
<a name="break"></a>
|
||||||
|
<code class=proc-def>break </code><var> pred clist -> [list clist]</var>
|
||||||
|
<dt class=proc-defn>
|
||||||
|
<a name="break!"></a>
|
||||||
|
<code class=proc-def>break!</code><var> pred list -> [list list]</var>
|
||||||
|
<dd class=proc-def>
|
||||||
|
|
||||||
|
<code>Span</code> splits the list into the longest initial prefix whose
|
||||||
|
elements all satisfy <var>pred</var>, and the remaining tail.
|
||||||
|
<code>Break</code> inverts the sense of the predicate:
|
||||||
|
the tail commences with the first element of the input list
|
||||||
|
that satisfies the predicate.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
In other words:
|
||||||
|
<code>span</code> finds the intial span of elements
|
||||||
|
satisfying <var>pred</var>,
|
||||||
|
and <code>break</code> breaks the list at the first element satisfying
|
||||||
|
<var>pred</var>.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<code>Span</code> is equivalent to
|
||||||
|
<pre class=code-example>
|
||||||
|
(values (take-while <var>pred</var> <var>clist</var>)
|
||||||
|
(drop-while <var>pred</var> <var>clist</var>))
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<code>Span!</code> and <code>break!</code> are the linear-update variants.
|
||||||
|
They are allowed, but not required,
|
||||||
|
to alter the argument list to produce the result.
|
||||||
|
|
||||||
|
<pre class=code-example>
|
||||||
|
(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)
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
==== any
|
==== any
|
||||||
============================================================================-->
|
============================================================================-->
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
The SRFI-1 list library -*- outline -*-
|
The SRFI-1 list library -*- outline -*-
|
||||||
Olin Shivers
|
Olin Shivers
|
||||||
98/10/16
|
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
|
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).
|
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.
|
- Use of a simple CHECK-ARG procedure for argument checking.
|
||||||
|
|
||||||
- It is written for clarity and well-commented. The current source is
|
- 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
|
- It is written for efficiency. Fast paths are provided for common
|
||||||
cases. Side-effecting procedures such as FILTER! avoid unnecessary,
|
cases. Side-effecting procedures such as FILTER! avoid unnecessary,
|
||||||
|
@ -137,13 +137,15 @@ Selectors
|
||||||
take drop
|
take drop
|
||||||
take-right drop-right
|
take-right drop-right
|
||||||
take! drop-right!
|
take! drop-right!
|
||||||
|
split-at split-at!
|
||||||
last last-pair
|
last last-pair
|
||||||
|
|
||||||
Miscellaneous: length, append, reverse, zip & count
|
Miscellaneous: length, append, concatenate, reverse, zip & count
|
||||||
# length
|
# length
|
||||||
length+
|
length+
|
||||||
# append reverse
|
# append reverse
|
||||||
append! reverse!
|
append! reverse!
|
||||||
|
concatenate concatenate!
|
||||||
append-reverse append-reverse!
|
append-reverse append-reverse!
|
||||||
zip unzip1 unzip2 unzip3 unzip4 unzip5
|
zip unzip1 unzip2 unzip3 unzip4 unzip5
|
||||||
count
|
count
|
||||||
|
@ -157,14 +159,16 @@ Fold, unfold & map
|
||||||
|
|
||||||
Filtering & partitioning
|
Filtering & partitioning
|
||||||
filter partition remove
|
filter partition remove
|
||||||
filter! partition! remove!
|
filter! partition! remove!
|
||||||
|
|
||||||
Searching
|
Searching
|
||||||
+ member
|
+ member
|
||||||
# memq memv
|
# memq memv
|
||||||
find find-tail
|
find
|
||||||
any every
|
any every
|
||||||
list-index
|
list-index
|
||||||
|
take-while drop-while take-while!
|
||||||
|
span break span! break!
|
||||||
|
|
||||||
Deleting
|
Deleting
|
||||||
delete delete-duplicates
|
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)
|
||||||
(take! (circular-list 1 3 5) 8) => (1 3 5 1 3 5 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 -> object
|
||||||
last-pair pair -> pair
|
last-pair pair -> pair
|
||||||
LAST returns the last element of the non-empty, finite list 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)
|
(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 list -> integer R5RS
|
||||||
length+ clist -> integer or #f
|
length+ clist -> integer or #f
|
||||||
|
@ -779,6 +797,25 @@ append! list1 ... -> value
|
||||||
the result list. The last argument is never altered; the result
|
the result list. The last argument is never altered; the result
|
||||||
list shares structure with this parameter.
|
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 R5RS
|
||||||
reverse! list -> list
|
reverse! list -> list
|
||||||
REVERSE returns a newly allocated list consisting of the elements of
|
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
|
Note: MIT Scheme and Haskell flip F's arg order for their REDUCE and
|
||||||
FOLD functions.
|
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 f ridentity list -> value
|
||||||
REDUCE-RIGHT is the fold-right variant of REDUCE.
|
REDUCE-RIGHT is the fold-right variant of REDUCE.
|
||||||
It obeys the following definition:
|
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).
|
...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:
|
UNFOLD constructs a list with the following loop:
|
||||||
(let lp ((seed seed) (lis tail))
|
(let lp ((seed seed) (lis tail))
|
||||||
(if (p seed) lis
|
(if (p seed) lis
|
||||||
|
@ -1003,82 +1098,40 @@ unfold p f g seed [tail] -> value
|
||||||
SEED: The "state" value for the unfold.
|
SEED: The "state" value for the unfold.
|
||||||
TAIL: list terminator; defaults to '().
|
TAIL: list terminator; defaults to '().
|
||||||
|
|
||||||
UNFOLD is the fundamental iterative list constructor, just as FOLD is the
|
In other words, we use G to generate a sequence of seed values
|
||||||
fundamental iterative list consumer. While UNFOLD may seem a bit abstract
|
SEED, (G SEED), (G^2 SEED), (G^3 SEED), ...
|
||||||
to novice functional programmers, it can be used in a number of ways:
|
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
|
UNFOLD-RIGHT is the fundamental iterative list constructor, just as FOLD
|
||||||
(lambda (x) (* x x))
|
is the fundamental iterative list consumer. While UNFOLD-RIGHT may seem a
|
||||||
(lambda (x) (- x 1))
|
bit abstract to novice functional programmers, it can be used in a number
|
||||||
10)
|
of ways:
|
||||||
|
|
||||||
(unfold null-list? car cdr lis) ; Reverse a proper list.
|
|
||||||
|
|
||||||
;; Read current input port into a list of values.
|
(unfold-right zero? ; List of squares: 1^2 ... 10^2
|
||||||
(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.
|
|
||||||
(lambda (x) (* x x))
|
(lambda (x) (* x x))
|
||||||
(lambda (x) (+ x 1))
|
(lambda (x) (- x 1))
|
||||||
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.
|
;; Read current input port into a list of values.
|
||||||
(unfold-right eof-object? values (lambda (x) (read)) (read))
|
(unfold-right eof-object? values (lambda (x) (read)) (read))
|
||||||
|
|
||||||
;; Copy a possibly non-proper list:
|
;; (APPEND-REVERSE rev-head tail)
|
||||||
(unfold-right not-pair? car cdr lis
|
(unfold-right null-list? car cdr rev-head tail)
|
||||||
values)
|
|
||||||
|
|
||||||
;; Append HEAD onto TAIL:
|
Interested functional programmers may enjoy noting that FOLD and
|
||||||
(unfold-right null-list? car cdr head
|
|
||||||
(lambda (x) tail))
|
|
||||||
|
|
||||||
|
|
||||||
Interested functional programmers may enjoy noting that FOLD-RIGHT and
|
|
||||||
UNFOLD-RIGHT are in some sense inverses. That is, given operations KNULL?,
|
UNFOLD-RIGHT are in some sense inverses. That is, given operations KNULL?,
|
||||||
KAR, KDR, KONS, and KNIL satisfying
|
KAR, KDR, KONS, and KNIL satisfying
|
||||||
(kons (kar x) (kdr x)) = x and (knull? knil) = #t
|
(kons (kar x) (kdr x)) = x and (knull? knil) = #t
|
||||||
then
|
then
|
||||||
(FOLD-RIGHT kons knil (UNFOLD-RIGHT knull? kar kdr x)) = x
|
(FOLD kons knil (UNFOLD-RIGHT knull? kar kdr x)) = x
|
||||||
and
|
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
|
This combinator presumably has some pretentious mathematical name;
|
||||||
explicit TAIL-GEN procedure is supplied, it is called an
|
interested readers are invited to communicate it to the author.
|
||||||
"apomorphism."
|
|
||||||
|
|
||||||
map proc clist1 clist2 ... -> list R5RS+
|
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)
|
(find-tail (lambda (elt) (equal? x elt)) lis)
|
||||||
|
|
||||||
In the circular-list case, this procedure "rotates" the list.
|
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
|
any pred clist1 clist2 ... -> value
|
||||||
Applies the predicate across the lists, returning true if the predicate
|
Applies the predicate across the lists, returning true if the predicate
|
||||||
|
|
Loading…
Reference in New Issue