For a type A,
a.as is the list whose head isA List
a , and whose tail isA
as .A List
nil is the empty list.A List
Of course one often sees iterated list expressions, which we display like
[1+2; 0; 4-2]
If the last tail-nested expression is not the constant
[1+2; 0; 4-2/ f(x)]
Here is a destructor for lists:
Case of X; nil e ; x.y
f(x,y)
It combines deciding emptiness with list splitting.
Case of nil; nil e ; x.y
f(x,y) *
e
Case of a.as; nil e ; x.y
f(x,y) *
f(a,as)
There are (derived) operations for treating lists as finite functions, namely a selector n}"
Thm* n:
, f:(
n
T), i:
n. (f{
n})[i] = f(i)
Thm* as:T List. (
i.as[i]){
||as||} = as
where
||as|| is list length.
Note on primitive recursion over lists.
There is a primitive, but little used, operation for doing recursion on lists. It is not much used because we tend to use more general methods for definingRecursive Functions but this specific recursion operator has some historical and pedagogical value. Also, in some other type systems, general recursion is not expressible, and such structural recursion operations must be built in.
Case of X; nil is the form of list recursion.b ; x.y, rec:v
f(x;y;v)
Case of nil; nil b ; x.y, rec:v
f(x;y;v) *
b
Case of a.as; nil b ; x.y, rec:v
f(x;y;v)
*![]()
f(a;as;Case of as; nilb ; x.y, rec:v
f(x;y;v))
Notice that there is a third argument to the list-splitting case; the application of the recursive function on the tail is passed in through it.
Actually, our(Case of X; nil operator is simply the special case of this recursion operator in which the recursion on the tail is ignored.e ; x.y
f(x,y))
About:
![]() | ![]() | ![]() | ![]() | ![]() |
![]() | ![]() | ![]() | ![]() | ![]() |
![]() |