Updated list library to most recent revision of the SRFI.

This commit is contained in:
shivers 1999-10-04 17:33:45 +00:00
parent 232ab91be9
commit 0f632e013b
4 changed files with 567 additions and 192 deletions

View File

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

View File

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

View File

@ -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 &amp; count <dt class=proc-index> Miscellaneous: length, append, concatenate, reverse, zip &amp; 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&nbsp;</code><var> x i -&gt; [list object]</var>
<dt class=proc-defn>
<a name="split-at!"></a>
<code class=proc-def>split-at!</code><var> x i -&gt; [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 &amp; count</a></h2> <h2><a name="Miscellaneous">Miscellaneous: length, append, concatenate, reverse, zip &amp; 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&nbsp;</code><var> list-of-lists -&gt; value</var>
<dt class=proc-defn>
<a name="concatenate!"></a>
<code class=proc-def>concatenate!</code><var> list-of-lists -&gt; 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] -&gt; list</var> <code class=proc-def>unfold</code><var> p f g seed [tail-gen] -&gt; 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) (&gt; 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] -&gt; 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] -&gt; 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) (&gt; 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&nbsp;</code><var> pred clist -&gt; list</var>
<dt class=proc-defn>
<a name="take-while!"></a>
<code class=proc-def>take-while!</code><var> pred clist -&gt; 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 -&gt; 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&nbsp;&nbsp;</code><var> pred clist -&gt; [list clist]</var>
<dt class=proc-defi>
<a name="span!"></a>
<code class=proc-def>span!&nbsp;</code><var> pred list&nbsp; -&gt; [list list]</var>
<dt class=proc-defi>
<a name="break"></a>
<code class=proc-def>break&nbsp;</code><var> pred clist -&gt; [list clist]</var>
<dt class=proc-defn>
<a name="break!"></a>
<code class=proc-def>break!</code><var> pred list&nbsp; -&gt; [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
============================================================================--> ============================================================================-->

View File

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