- collect-first #!optional (sentinel #f)procedure
- collect-last #!optional (sentinel #f)procedure
A collector that returns either the first or last item of the collection only. first will terminate early after collecting the first item.
(import transducers) (transduce list-fold (filter odd?) (collect-first) (list 2 4 6 8 11 13 1 2 4)) ; => 11 (transduce list-fold (filter odd?) (collect-last) (list 2 4 6 8 11 13 1 2 4)) ; => 1
collect-first in particular is very useful as a collector. By combining the collect-first collector and the filter transducer, we can implement a "find" operation on a collection:
(import transducers) (transduce list-fold (filter (lambda (x) (eq? x 'c))) (collect-first) (list 'b 'c 'd 'c)) ; => 'c
What's more, collect-first and collect-last are also very useful with sentinel values. If collect-first or collect-last fail to find any items (say, because you filtered them out), then usually they return false:
(import transducers) (transduce list-fold (filter odd?) (collect-first) (list 2 4 6 8)) ; => #f
This is not too dissimilar from most find operations in Scheme. However, #f can sometimes be ambiguous. If you were extracting the value from an a-list as follows:
(import transducers) (transduce list-fold (compose (filter (lambda (kv-pair) (eq? (car kv-pair) 'bar))) (map cdr)) (collect-first) (list (cons 'foo 1) (cons 'bar #f) (cons 'baz "abcd"))) ; => #f
then we can see that #f is ambiguous. Instead, we can use a custom sentinel value, for example the sentinel (nothing) from SRFI-189:
(import transducers srfi-189) (transduce list-fold (compose (filter (lambda (kv-pair) (eq? (car kv-pair) 'bar))) (map cdr)) (collect-first) (list (cons 'foo 1) (cons 'bar #f) (cons 'baz "abcd"))) ; => #f (transduce list-fold (compose (filter (lambda (kv-pair) (eq? (car kv-pair) 0))) (map cdr)) (collect-first (nothing)) (list (cons 'foo 1) (cons 'bar #f) (cons 'baz "abcd"))) ; => #<srfi-189#<nothing>>
This way, one can use the custom sentinel value to distinguish between ambiguous #f returns.