structure Fold01N = struct fun fold {finish, start, zero} = Fold.fold ((id, finish, fn () => zero, start), fn (finish, _, p, _) => finish (p ())) fun step0 {combine, input} = Fold.step0 (fn (_, finish, _, f) => (finish, finish, fn () => f input, fn x' => combine (f input, x'))) fun step1 {combine} z input = step0 {combine = combine, input = input} z end
If one has a value zero, and functions start, c, and finish, then one can define a variable-arity function f and stepper ` as follows.
val f = fn z => Fold01N.fold {finish = finish, start = start, zero = zero} z val ` = fn z => Fold01N.step1 {combine = c} z
One can then use the fold equation to prove the following equations.
f $ = zero f `a1 $ = finish (start a1) f `a1 `a2 $ = finish (c (start a1, a2)) f `a1 `a2 `a3 $ = finish (c (c (start a1, a2), a3)) ...
For an example of Fold01N, see VariableArityPolymorphism.
Typing Fold01N
Here is the signature for Fold01N. We use a trick to avoid having to duplicate the definition of some rather complex types in both the signature and the structure. We first define the types in a structure. Then, we define them via type re-definitions in the signature, and via open in the full structure.
structure Fold01N = struct type ('input, 'accum1, 'accum2, 'answer, 'zero, 'a, 'b, 'c, 'd, 'e) t = (('zero -> 'zero) * ('accum2 -> 'answer) * (unit -> 'zero) * ('input -> 'accum1), ('a -> 'b) * 'c * (unit -> 'a) * 'd, 'b, 'e) Fold.t type ('input1, 'accum1, 'input2, 'accum2, 'a, 'b, 'c, 'd, 'e, 'f) step0 = ('a * 'b * 'c * ('input1 -> 'accum1), 'b * 'b * (unit -> 'accum1) * ('input2 -> 'accum2), 'd, 'e, 'f) Fold.step0 type ('accum1, 'input, 'accum2, 'a, 'b, 'c, 'd, 'e, 'f, 'g) step1 = ('a, 'b * 'c * 'd * ('a -> 'accum1), 'c * 'c * (unit -> 'accum1) * ('input -> 'accum2), 'e, 'f, 'g) Fold.step1 end signature FOLD_01N = sig type ('a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j) t = ('a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j) Fold01N.t type ('a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j) step0 = ('a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j) Fold01N.step0 type ('a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j) step1 = ('a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j) Fold01N.step1 val fold: {finish: 'accum2 -> 'answer, start: 'input -> 'accum1, zero: 'zero} -> ('input, 'accum1, 'accum2, 'answer, 'zero, 'a, 'b, 'c, 'd, 'e) t val step0: {combine: 'accum1 * 'input2 -> 'accum2, input: 'input1} -> ('input1, 'accum1, 'input2, 'accum2, 'a, 'b, 'c, 'd, 'e, 'f) step0 val step1: {combine: 'accum1 * 'input -> 'accum2} -> ('accum1, 'input, 'accum2, 'a, 'b, 'c, 'd, 'e, 'f, 'g) step1 end structure Fold01N: FOLD_01N = struct open Fold01N fun fold {finish, start, zero} = Fold.fold ((id, finish, fn () => zero, start), fn (finish, _, p, _) => finish (p ())) fun step0 {combine, input} = Fold.step0 (fn (_, finish, _, f) => (finish, finish, fn () => f input, fn x' => combine (f input, x'))) fun step1 {combine} z input = step0 {combine = combine, input = input} z end