**Common Lisp the Language, 2nd Edition**

Transducers compute series from series and form the heart of most series
expressions. Mapping is by far the most common transducer. This section
presents a number of additional simple transducers.

**[Function]**

`cotruncate &rest series-inputs `

Each of these functions accepts one or more series inputs *S1*, **...**, *Sn* as its `&rest` argument and returns ** n** series
outputs

(cotruncate #Z(1 2 -3 4) #Z(a b c)) => #Z(1 2 -3) and #Z(a b c) (until #Z(nil nil t nil) #Z(1 2 -3 4) #Z(a b c)) => #Z(1 2) and #Z(a b) (until-if #'minusp #Z(1 2 -3 4) #Z(a b c)) => #Z(1 2) and #Z(a b)

**[Function]**

`previous items &optional (default nil) (amount 1)`

The series returned by `previous` is the same as the input series
*items* except that it is shifted to the right by the positive
integer *amount*. The shifting is done by inserting *amount*
copies of *default* before *items* and discarding *amount*
elements from the end of *items*.

(previous #Z(10 11 12) 0) => #Z(0 10 11)

**[Function]**

`latch items &key :after :before :pre :post`

The series returned by `latch` is the same as the input series
*items* except that some of the elements are replaced by other
values. `latch` acts like a *latch* electronic circuit
component. Each input element causes the creation of a corresponding
output element. After a specified number of non-null input elements
have been encountered, the latch is triggered and the output mode is
permanently changed.

The `:after` and `:before` arguments specify the latch point.
The latch point is just after the `:after`-th non-null element in
*items* or just before the `:before`-th non-null element. If
neither `:after` nor `:before` is specified, an `:after`
of `1` is assumed. If both are specified, it is an error.

If a `:pre` is specified, every element prior to the latch point
is replaced by this value. If a `:post` is specified, every element
after the latch point is replaced by this value. If neither is
specified, a `:post` of `nil` is assumed.

(latch #Z(nil c nil d e)) => #Z(nil c nil nil nil) (latch #Z(nil c nil d e) :before 2 :post t) => #Z(nil c nil t t)

**[Function]**

`collecting-fn type init function &rest series-inputs`

The higher-order function `collecting-fn` supports the general concept of
a simple transducer with internal state. The *type* argument is a type
specifier indicating the type of values returned by *function*.
The `values` construct can be used to indicate multiple types; however,
*type* cannot indicate zero values. If *type* indicates ** m** types
,
then

The *init* must be of type
`(function () (values ... ))`.

The *function* must be of type

(function ( ... ... ) (values ... ))

The length of each output is the same as the length of the shortest input.
If there are no bounded series inputs, the outputs are unbounded.
The elements of the *Ti* are computed as follows:

(valuesT1...Tm) == (multiple-value-callfunction(funcallinit)S1...Sn) (valuesT1...Tm) == (funcallfunctionT1...TmS1...Sn)

If *init* or *function* has side effects, it can count on
being called in the order indicated by the equations above. However,
given the lazy evaluation nature of series, these functions will not be called
until their outputs are actually used (if ever). In addition, no
assumptions can be made about the relative order of evaluation of these
calls with regard to execution in other parts of a given series expression.
The second example below computes a series of partial sums of the numbers in
an input series. The third example computes two output series: the
partial sums of its first input and the partial products of its second
input.

(defun running-averages (float-list) (multiple-value-call #'map-fn 'float #'/ (collecting-fn '(values float integer) #'(lambda () (values 0.0 0) #'(lambda (s n x) (values (+ s x) (+ n 1)))) float-list)))

(collecting-fn 'integer #'(lambda () 0) #'+ #Z(1 2 3)) => #Z(1 3 6) (collecting-fn '(values integer integer) #'(lambda () (values 0 1)) #'(lambda (sum prod x y) (values (+ sum x) (* prod y))) #Z(4 6 8) #Z(1 2 3)) => #Z(4 10 18) and #Z(1 2 6)

[email protected]