Magic Pipes
Documentation
Login

mpfold [-n integer] [-a expr] [-t] [-o expr] expr [expr]

The first expression evaluates to a two-argument procedure, the second (the initial accumulator) to any value; an unspecified value is the default if none is specified. -o specifies a single-argument output procedure; the identity function is the default.

Applies the procedure to each s-expression from the input in turn, with the current accumulator as the second argument. At the end, outputs the result of applying the output procedure to the final accumulator.

If -n is specified, then rather than just the single "current input s-expression", the first expression's procedure is passed the specified number of previous s-expressions as well, in extra arguments. -n defaults to 0. The first call to the procedure will be performed when sufficient s-expressions have been read (eg, -n+1 s-expressions) unless -a is specified, when the procedure will be called for every s-expression, with the result of the expression passed to -a used as a "default" for slots that cannot yet be filled.

If -t is specified, then the current, and the specified number of previous, sexprs are passed as a single list, rather than as separate arguments to the procedure. The procedure is called for every input s-expression, with the list being truncated if sufficient previous values are not available; -a is ignored.

current-input-port is banned, but current-error-port and current-output-port are accessible.

As with mpmap, the final result of the output procedure may be any number of values, which will be output sensibly.

Examples

Basic operation

$ echo "1 2 3" | mpfold + 0
6

Using -o

$ echo "1 2 3" | mpfold -o 'number->string' + 0
"6"
$ echo "1 2 3" | mpfold -o '(lambda (x) (* x 2))' + 0
12

Using mplog to demonstrate how the fold-proc is called

$ echo "1 2 3 4 5 6" | mpfold '(lambda x (mplog "~S" x) 0)' 0
(1 0)
(2 0)
(3 0)
(4 0)
(5 0)
(6 0)
0

The fold-proc is called with two arguments - the current input s-expr and the accumulator value.

Adding context with -n

$ echo "1 2 3 4 5 6" | mpfold -n 2 '(lambda x (mplog "~S" x) 0)' 0
(3 2 1 0)
(4 3 2 0)
(5 4 3 0)
(6 5 4 0)
0

Note how the fold-proc is not called for 1 or 2; the first value passed to it is 3 with 2 and 1 as the two requested context items. The fold-proc is now called with four arguments; the current item, the previous two items, and the accumulator value.

Using -a as the default context

$ echo "1 2 3 4 5 6" | mpfold -n 2 -a '#f' '(lambda x (mplog "~S" x) 0)' 0
(1 #f #f 0)
(2 1 #f 0)
(3 2 1 0)
(4 3 2 0)
(5 4 3 0)
(6 5 4 0)
0

Note how the fold-proc is now called for all the input sexprs, with #f filling in for "missing context".

Using -t to pass a list into the fold-proc

$ echo "1 2 3 4 5 6" | mpfold -n 2 -t '(lambda x (mplog "~S" x) 0)' 0
((1) 0)
((2 1) 0)
((3 2 1) 0)
((4 3 2) 0)
((5 4 3) 0)
((6 5 4) 0)
0

The fold-proc now receives two arguments again; the first is a list containing the current input sexpr and up to 2 (as requested by -n) previous ones. We are invoked for every input s-expression, and the list is simply shorter if there have not been two previous sexprs yet.

Moving average with final mean

$ echo "3 7 2 4 6 4 1" | mpfold -n 2 \
       -o '(lambda (x) `(mean ,(/ (cdr x) (car x))))' \
       '(lambda (x h1 h2 acc) (write `(moving-mean ,(/ (+ x h1 h2) 3))) (newline) (if acc (cons (+ (car acc) 1) (+ (cdr acc) x)) (cons 3 (+ x h1 h2))))' '#f'
(moving-mean 4)
(moving-mean 4.33333333333333)
(moving-mean 4)
(moving-mean 4.66666666666667)
(moving-mean 3.66666666666667)
(mean 3.85714285714286)

Computing the final mean correctly when using -n without -a is a little complicated.

Here's a simpler way:

$ echo "3 7 2 4 6 4 1" | mpfold -n 2 -a '#f' \
       -o '(lambda (x) `(mean ,(/ (cdr x) (car x))))' \
       '(lambda (x h1 h2 acc) (when (and h1 h2) (write `(moving-mean ,(/ (+ x h1 h2) 3))) (newline)) (cons (+ (car acc) 1) (+ (cdr acc) x)))' '(0 . 0)'
(moving-mean 4)
(moving-mean 4.33333333333333)
(moving-mean 4)
(moving-mean 4.66666666666667)
(moving-mean 3.66666666666667)
(mean 3.85714285714286)