The goal of this lecture note is to demonstrate how nat_fold_left and list_fold_left abstract the pattern of tail-recursive functions that use an accumulator for Peano numbers and for lists.
Let us revisit the tail-recursive addition function, which is defined recursively over its first argument and uses its second as an accumulator:
Definition tr_add (n m : nat) : nat :=
let fix visit i a :=
match i with
O =>
a
| S i' =>
visit i' (S a)
end
in visit n m.
Let us revisit the tail-recursive power function, which is defined recursively over its second argument and uses an accumulator:
Definition tr_power (x n : nat) : nat :=
let fix visit i a :=
match i with
O =>
a
| S n' =>
visit n' (x * a)
end
in visit n 1.
The two tail-recursive functions above share a common pattern:
Definition ... (n : nat) ... : ... :=
let fix visit i a :=
match i with
O =>
a
| S n' =>
visit n' (... a ...)
end
in visit n ... .
Indeed,
So,
we obtain the following implementation:
Definition nat_fold_left (V : Type) (zero_case : V) (succ_case : V -> V) (n : nat) : V :=
let fix visit i a :=
match i with
O =>
a
| S n' =>
visit n' (succ_case a)
end
in visit n zero_case.
Then, we can
to obtain the following defition of the addition function as an instance of nat_fold_left:
Definition tr_add_left (n m : nat) : nat :=
nat_fold_left
nat
m
(fun ih => S ih)
n.
Likewise, we can
to obtain the following defition of the power function as an instance of nat_fold_left:
Definition tr_power_left (x n : nat) : nat :=
nat_fold_left
nat
1
(fun ih => x * ih)
n.