]> matita.cs.unibo.it Git - helm.git/blob - weblib/tutorial/chapter3.ma
commit by user andrea
[helm.git] / weblib / tutorial / chapter3.ma
1 include "tutorial/chapter2.ma".
2 include "basics/bool.ma".
3
4 (* Matita supports polymorphic data types. The most typical case are polymorphic
5 lists, parametric in the type of their elements: *)
6
7 inductive list (A:Type[0]) : Type[0] ≝
8   | nil: list A
9   | cons: A -> list A -> list A.
10
11 (* The type notation list A is the type of all lists with elements of type A: it is
12 defined by two constructors: a polymorphic empty list (nil A) and a cons operation, 
13 adding a new head element of type A to a previous list. For instance, (list nat) and
14 and (list bool) are lists of natural numbers and booleans, respectively. But we can
15 also form more complex data types, like (list (list (nat → nat))), that is a list whose
16 elements are lists of functions from natural numbers to natural numbers.
17
18 Typical elements in (list bool) are for instance,
19   nil nat                                      - the empty list of type nat
20   cons nat true (nil nat)                      - the list containing true
21   cons nat false (cons nat (true (nil nat)))   - the list containing false and true
22 and so on. 
23
24 Note that both constructos nil and cons are expecting in input the type parameter -
25 in this case, bool.
26
27 We now add a bit of notation, in order to make the syntax more readable. In particular,
28 we would like to write [] instead of (nil A) and a::l instead of (cons A a l), leaving
29 the system the burden to infer A, whenever possible.
30 *)
31
32 notation "hvbox(hd break :: tl)"
33   right associative with precedence 47
34   for @{'cons $hd $tl}.
35
36 notation "[ list0 x sep ; ]"
37   non associative with precedence 90
38   for ${fold right @'nil rec acc @{'cons $x $acc}}.
39
40 notation "hvbox(l1 break @ l2)"
41   right associative with precedence 47
42   for @{'append $l1 $l2 }.
43
44 interpretation "nil" 'nil = (nil ?).
45 interpretation "cons" 'cons hd tl = (cons ? hd tl).
46
47 (* Let us define a few basic functions over lists. Our first example is the append 
48 function, concatenating two lists l1 and l2. The natural way is to proceed by recursion
49 on l1: if it is empty the result is simply l2, while if l1 = hd::tl then we
50 recursively append tl and l2 , and then add hd as first element. Note that the append
51 function itself is polymorphic, and the first argument it takes in input is the type
52 A of the elements of two lists l1 and l2. 
53 Moreover, since the append function takes in input several parameters, we must also 
54 specify in the its defintion on which one of them we are recurring: in this case l1.
55 If not othewise specified, recursion is supposed to act on the first argument of the
56 function.*)
57
58 let rec append A (l1: \ 5a href="cic:/matita/tutorial/chapter3/list.ind(1,0,1)"\ 6list\ 5/a\ 6 A) l2 on l1 ≝ 
59   match l1 with
60   [ nil ⇒  l2
61   | cons hd tl ⇒  hd \ 5a title="cons" href="cic:/fakeuri.def(1)"\ 6:\ 5/a\ 6: append A tl l2 ].
62
63 interpretation "append" 'append l1 l2 = (append ? l1 l2).
64
65 (* As usual, the function is executable. For instance, (append A nil l) reduces to
66 l, as shown by the following example: *)
67
68 example nil_append: ∀A.∀l:\ 5a href="cic:/matita/tutorial/chapter3/list.ind(1,0,1)"\ 6list\ 5/a\ 6 A. \ 5a title="nil" href="cic:/fakeuri.def(1)"\ 6[\ 5/a\ 6\ 5a title="append" href="cic:/fakeuri.def(1)"\ 6@\ 5/a\ 6 l \ 5a title="leibnitz's equality" href="cic:/fakeuri.def(1)"\ 6=\ 5/a\ 6 l.
69 #A #l normalize // qed.
70
71 (* Proving that l @ [] = l is just a bit more complex. The situation is exactly the 
72 same as for the addition operation of the previous chapter: since append is defined
73 by recutsion over the first argument, the computation of l @ [] is stuck, and we must 
74 proceed by induction on l *) 
75
76 lemma append_nil: ∀A.∀l:\ 5a href="cic:/matita/tutorial/chapter3/list.ind(1,0,1)"\ 6list\ 5/a\ 6 A.l \ 5a title="append" href="cic:/fakeuri.def(1)"\ 6@\ 5/a\ 6 \ 5a title="nil" href="cic:/fakeuri.def(1)"\ 6[\ 5/a\ 6\ 5a title="leibnitz's equality" href="cic:/fakeuri.def(1)"\ 6=\ 5/a\ 6 l.
77 #A #l (elim l) normalize // qed.
78
79 (* similarly, we can define the two functions head and tail. Since we can only define
80 total functions, we should decide what to do in case the input list is empty. For tl, it 
81 is natural to return the empty list; for hd, we take in input a default element d of type 
82 A to return in this case. *)
83
84 definition head ≝ λA.λl: \ 5a href="cic:/matita/tutorial/chapter3/list.ind(1,0,1)"\ 6list\ 5/a\ 6 A.λd:A.
85   match l with [ nil ⇒ d | cons a _ ⇒ a].
86
87 definition tail ≝  λA.λl: \ 5a href="cic:/matita/tutorial/chapter3/list.ind(1,0,1)"\ 6list\ 5/a\ 6 A.
88   match l with [ nil ⇒  \ 5a title="nil" href="cic:/fakeuri.def(1)"\ 6[\ 5/a\ 6] | cons hd tl ⇒  tl].
89
90 example ex_head: ∀A.∀a,d,l. \ 5a href="cic:/matita/tutorial/chapter3/head.def(1)"\ 6head\ 5/a\ 6 A (a\ 5a title="cons" href="cic:/fakeuri.def(1)"\ 6:\ 5/a\ 6:l) d \ 5a title="leibnitz's equality" href="cic:/fakeuri.def(1)"\ 6=\ 5/a\ 6 a.
91 #A #a #d #l normalize // qed.
92
93 (* Problemi con la notazione *)
94 example ex_tail: \ 5a href="cic:/matita/tutorial/chapter3/tail.def(1)"\ 6tail\ 5/a\ 6 ? (\ 5a href="cic:/matita/tutorial/chapter3/list.con(0,2,1)"\ 6cons\ 5/a\ 6 ? \ 5a href="cic:/matita/basics/bool/bool.con(0,1,0)"\ 6true\ 5/a\ 6 \ 5a title="nil" href="cic:/fakeuri.def(1)"\ 6[\ 5/a\ 6]) \ 5a title="leibnitz's equality" href="cic:/fakeuri.def(1)"\ 6=\ 5/a\ 6 \ 5a title="nil" href="cic:/fakeuri.def(1)"\ 6[\ 5/a\ 6].
95 normalize // qed.
96
97 theorem associative_append: 
98 ∀A.∀l1,l2,l3: \ 5a href="cic:/matita/tutorial/chapter3/list.ind(1,0,1)"\ 6list\ 5/a\ 6 A. (l1 \ 5a title="append" href="cic:/fakeuri.def(1)"\ 6@\ 5/a\ 6 l2) \ 5a title="append" href="cic:/fakeuri.def(1)"\ 6@\ 5/a\ 6 l3 \ 5a title="leibnitz's equality" href="cic:/fakeuri.def(1)"\ 6=\ 5/a\ 6 l1 \ 5a title="append" href="cic:/fakeuri.def(1)"\ 6@\ 5/a\ 6 (l2 \ 5a title="append" href="cic:/fakeuri.def(1)"\ 6@\ 5/a\ 6 l3).
99 #A #l1 #l2 #l3 (elim l1) normalize // qed.
100
101 (* Problemi con la notazione *)
102 theorem append_cons:
103 ∀A.∀a:A.∀l,l1: \ 5a href="cic:/matita/tutorial/chapter3/list.ind(1,0,1)"\ 6list\ 5/a\ 6 A.l\ 5a title="append" href="cic:/fakeuri.def(1)"\ 6@\ 5/a\ 6(a\ 5a title="cons" href="cic:/fakeuri.def(1)"\ 6:\ 5/a\ 6:l1)\ 5a title="leibnitz's equality" href="cic:/fakeuri.def(1)"\ 6=\ 5/a\ 6 (l \ 5a title="append" href="cic:/fakeuri.def(1)"\ 6@\ 5/a\ 6 (\ 5a href="cic:/matita/tutorial/chapter3/list.con(0,2,1)"\ 6cons\ 5/a\ 6 ? a \ 5a title="nil" href="cic:/fakeuri.def(1)"\ 6[\ 5/a\ 6])) \ 5a title="append" href="cic:/fakeuri.def(1)"\ 6@\ 5/a\ 6 l1.
104 /2/ qed. 
105
106 (* Other typical functions over lists are those computing the length 
107 of a list, and the function returning the nth element *)
108
109 let rec length (A:Type[0]) (l:\ 5a href="cic:/matita/tutorial/chapter3/list.ind(1,0,1)"\ 6list\ 5/a\ 6 A) on l ≝ 
110 match l with 
111   [ nil ⇒ \ 5a href="cic:/matita/tutorial/chapter2/nat.con(0,1,0)"\ 6O\ 5/a\ 6
112     | cons a tl ⇒ \ 5a href="cic:/matita/tutorial/chapter2/nat.con(0,2,0)"\ 6S\ 5/a\ 6 (length A tl)].
113
114 let rec nth n (A:Type[0]) (l:\ 5a href="cic:/matita/tutorial/chapter3/list.ind(1,0,1)"\ 6list\ 5/a\ 6 A) (d:A)  ≝  
115   match n with
116     [O ⇒ \ 5a href="cic:/matita/tutorial/chapter3/head.def(1)"\ 6head\ 5/a\ 6 A l d
117     |S m ⇒ nth m A (\ 5a href="cic:/matita/tutorial/chapter3/tail.def(1)"\ 6tail\ 5/a\ 6 A l) d].
118
119 example ex_length: \ 5a href="cic:/matita/tutorial/chapter3/length.fix(0,1,1)"\ 6length\ 5/a\ 6 ? (\ 5a href="cic:/matita/tutorial/chapter3/list.con(0,2,1)"\ 6cons\ 5/a\ 6 ? \ 5a href="cic:/matita/tutorial/chapter2/nat.con(0,1,0)"\ 6O\ 5/a\ 6 \ 5a title="nil" href="cic:/fakeuri.def(1)"\ 6[\ 5/a\ 6]) \ 5a title="leibnitz's equality" href="cic:/fakeuri.def(1)"\ 6=\ 5/a\ 6 \ 5a href="cic:/matita/tutorial/chapter2/nat.con(0,2,0)"\ 6S\ 5/a\ 6 \ 5a href="cic:/matita/tutorial/chapter2/nat.con(0,1,0)"\ 6O\ 5/a\ 6.
120 normalize // qed.
121
122 example ex_nth: \ 5a href="cic:/matita/tutorial/chapter3/nth.fix(0,0,2)"\ 6nth\ 5/a\ 6 (\ 5a href="cic:/matita/tutorial/chapter2/nat.con(0,2,0)"\ 6S\ 5/a\ 6 \ 5a href="cic:/matita/tutorial/chapter2/nat.con(0,1,0)"\ 6O\ 5/a\ 6) ? (\ 5a href="cic:/matita/tutorial/chapter3/list.con(0,2,1)"\ 6cons\ 5/a\ 6 ? (\ 5a href="cic:/matita/tutorial/chapter2/nat.con(0,2,0)"\ 6S\ 5/a\ 6 \ 5a href="cic:/matita/tutorial/chapter2/nat.con(0,1,0)"\ 6O\ 5/a\ 6) (\ 5a href="cic:/matita/tutorial/chapter3/list.con(0,2,1)"\ 6cons\ 5/a\ 6 ? \ 5a href="cic:/matita/tutorial/chapter2/nat.con(0,1,0)"\ 6O\ 5/a\ 6 \ 5a title="nil" href="cic:/fakeuri.def(1)"\ 6[\ 5/a\ 6])) \ 5a href="cic:/matita/tutorial/chapter2/nat.con(0,1,0)"\ 6O\ 5/a\ 6 \ 5a title="leibnitz's equality" href="cic:/fakeuri.def(1)"\ 6=\ 5/a\ 6 \ 5a href="cic:/matita/tutorial/chapter2/nat.con(0,1,0)"\ 6O\ 5/a\ 6.
123 normalize // qed.
124
125 (* Proving that the length of l1@l2 is the sum of the lengths of l1
126 and l2 just requires a trivial induction on the first list. *)
127
128  lemma  length_add: ∀A.∀l1,l2:\ 5a href="cic:/matita/tutorial/chapter3/list.ind(1,0,1)"\ 6list\ 5/a\ 6 A. 
129   \ 5a href="cic:/matita/tutorial/chapter3/length.fix(0,1,1)"\ 6length\ 5/a\ 6 ? (l1\ 5a title="append" href="cic:/fakeuri.def(1)"\ 6@\ 5/a\ 6l2) \ 5a title="leibnitz's equality" href="cic:/fakeuri.def(1)"\ 6=\ 5/a\ 6 \ 5a href="cic:/matita/tutorial/chapter2/add.fix(0,0,1)"\ 6add\ 5/a\ 6 (\ 5a href="cic:/matita/tutorial/chapter3/length.fix(0,1,1)"\ 6length\ 5/a\ 6 ? l1) (\ 5a href="cic:/matita/tutorial/chapter3/length.fix(0,1,1)"\ 6length\ 5/a\ 6 ? l2).
130 #A #l1 elim l1 normalize // qed. 
131
132 (* Let us come to a more interesting question. How can we prove that the empty list is 
133 different from any list with at least one element, that is from any list of the kind (a::l)?
134 We start defining a simple predicate stating if a list is empty or not. The predicate
135 is computed by inspection over the list *)
136
137 definition is_nil: ∀A:Type[0].\ 5a href="cic:/matita/tutorial/chapter3/list.ind(1,0,1)"\ 6list\ 5/a\ 6 A → Prop ≝
138 λA.λl.match l with [ nil ⇒ l \ 5a title="leibnitz's equality" href="cic:/fakeuri.def(1)"\ 6=\ 5/a\ 6 \ 5a title="nil" href="cic:/fakeuri.def(1)"\ 6[\ 5/a\ 6] | cons hd tl ⇒ (l \ 5a title="leibnitz's non-equality" href="cic:/fakeuri.def(1)"\ 6\ 5/a\ 6 \ 5a title="nil" href="cic:/fakeuri.def(1)"\ 6[\ 5/a\ 6])].
139
140 (* Next we need a simple result about negation: if you wish to prove ¬P you are
141 authorized to add P to your hypothesis: *)
142
143 lemma neg_aux : ∀P:Prop. (P → \ 5a title="logical not" href="cic:/fakeuri.def(1)"\ 6¬\ 5/a\ 6P) → \ 5a title="logical not" href="cic:/fakeuri.def(1)"\ 6¬\ 5/a\ 6P.
144 #P #PtonegP % /3/ qed. 
145
146 theorem diff_cons_nil:
147 ∀A:Type[0].∀l:\ 5a href="cic:/matita/tutorial/chapter3/list.ind(1,0,1)"\ 6list\ 5/a\ 6 A.∀a:A. a\ 5a title="cons" href="cic:/fakeuri.def(1)"\ 6:\ 5/a\ 6:l \ 5a title="leibnitz's non-equality" href="cic:/fakeuri.def(1)"\ 6\ 5/a\ 6 \ 5a title="nil" href="cic:/fakeuri.def(1)"\ 6[\ 5/a\ 6].
148 #A #l #a @\ 5a href="cic:/matita/tutorial/chapter3/neg_aux.def(3)"\ 6neg_aux\ 5/a\ 6 #Heq 
149 (* we start assuming the new hypothesis Heq of type a::l = [] using neg_aux. 
150 Next we use the change tactic to pass from the current goal a::l≠ [] to the expression 
151 is_nil a::l, convertible with it. *)
152 (change with (\ 5a href="cic:/matita/tutorial/chapter3/is_nil.def(1)"\ 6is_nil\ 5/a\ 6 ? (a\ 5a title="cons" href="cic:/fakeuri.def(1)"\ 6:\ 5/a\ 6:l))) 
153 (* Now, we rewrite with Heq, obtaining (is_nil A []), that reduces to the trivial 
154 goal [] = [] *)
155 >Heq // qed.
156
157 (* As an application of the previous result let us prove that l1@l2 is empty if and 
158 only if both l1 and l2 are empty. The idea is to proceed by cases on l1: if l1=[] the
159 statement is trivial; on the other side, if l1 = a::tl, then the hypothesis 
160 (a::tl)@l2 = [] is absurd, hence we can prove anything from it. When we know we can
161 prove both A and ¬A, a sensible way to proceed is to apply False_ind: ∀P.False → P to the 
162 current goal, that breaks down to prove False, and then absurd: ∀A:Prop. A → ¬A → False 
163 to reduce to the contradictory cases. Usually, you may invoke automation to take care 
164 to solve the absurd case. *)
165
166 lemma nil_to_nil:  ∀A.∀l1,l2:\ 5a href="cic:/matita/tutorial/chapter3/list.ind(1,0,1)"\ 6list\ 5/a\ 6 \ 5span style="text-decoration: underline;"\ 6\ 5/span\ 6A.
167   l1\ 5a title="append" href="cic:/fakeuri.def(1)"\ 6@\ 5/a\ 6l2 \ 5a title="leibnitz's equality" href="cic:/fakeuri.def(1)"\ 6=\ 5/a\ 6 \ 5a title="nil" href="cic:/fakeuri.def(1)"\ 6[\ 5/a\ 6] → l1 \ 5a title="leibnitz's equality" href="cic:/fakeuri.def(1)"\ 6=\ 5/a\ 6 \ 5a title="nil" href="cic:/fakeuri.def(1)"\ 6[\ 5/a\ 6\ 5a title="logical and" href="cic:/fakeuri.def(1)"\ 6\ 5/a\ 6 l2 \ 5a title="leibnitz's equality" href="cic:/fakeuri.def(1)"\ 6=\ 5/a\ 6 \ 5a title="nil" href="cic:/fakeuri.def(1)"\ 6[\ 5/a\ 6].
168 #A #l1 cases l1 normalize /2/ #a #tl #l2 #H @\ 5a href="cic:/matita/basics/logic/False_ind.fix(0,1,1)"\ 6False_ind\ 5/a\ 6 /2/ qed. 
169
170 (* Let us come to some important, higher order, polymorphic functionals 
171 acting over lists. A typical example is the map function, taking a function
172 f:A → B, a list l = [a1; a2; ... ; an] and returning the list 
173 [f a1; f a2; ... ; f an]. *)
174
175 let rec map (A,B:Type[0]) (f: A → B) (l:\ 5a href="cic:/matita/tutorial/chapter3/list.ind(1,0,1)"\ 6list\ 5/a\ 6 A) on l: \ 5a href="cic:/matita/tutorial/chapter3/list.ind(1,0,1)"\ 6list\ 5/a\ 6 B ≝
176  match l with [ nil ⇒ \ 5a title="nil" href="cic:/fakeuri.def(1)"\ 6[\ 5/a\ 6] | cons x tl ⇒ f x \ 5a title="cons" href="cic:/fakeuri.def(1)"\ 6:\ 5/a\ 6: (map A B f tl)].
177
178 (* Another major example is the fold function, that taken a list 
179 l = [a1; a2; ... ;an], a base value b:B, and a function f: A → B → B returns 
180 (f a1 (f a2 (... (f an b)...))). *)
181
182 let rec foldr (A,B:Type[0]) (f:A → B → B) (b:B) (l:\ 5a href="cic:/matita/tutorial/chapter3/list.ind(1,0,1)"\ 6list\ 5/a\ 6 A) on l :B ≝  
183   match l with [ nil ⇒ b | cons a l ⇒ f a (foldr A B f b l)].
184
185 (* As an example of application of foldr, let us use it to define a filter function 
186 that given a list l: list A and a boolean test p:A → bool returns the sublist of elements 
187 satisfying the test. In this case, the result type B of foldr should be (list A), the base
188 value is [], and f: A → list A →list A is the function that taken x and l returns x::l, if
189 x satisfies the test, and l otherwise. We use an if_then_else function included from 
190 bbol.ma to this purpose. *)
191
192 definition filter ≝ 
193   λT.λp:T → \ 5a href="cic:/matita/basics/bool/bool.ind(1,0,0)"\ 6bool\ 5/a\ 6.
194   \ 5a href="cic:/matita/tutorial/chapter3/foldr.fix(0,4,1)"\ 6foldr\ 5/a\ 6 T (\ 5a href="cic:/matita/tutorial/chapter3/list.ind(1,0,1)"\ 6list\ 5/a\ 6 T) (λx,l0.\ 5a href="cic:/matita/basics/bool/if_then_else.def(1)"\ 6if_then_else\ 5/a\ 6 ? (p x) (x\ 5a title="cons" href="cic:/fakeuri.def(1)"\ 6:\ 5/a\ 6:l0) l0) \ 5a title="nil" href="cic:/fakeuri.def(1)"\ 6[\ 5/a\ 6].
195
196 (* Here are a couple of simple lemmas on the behaviour of the filter function. 
197 It is often convenient to state such lemmas, in order to be able to use rewriting
198 as an alternative to reduction in proofs: reduction is a bit difficult to control.
199 *)
200
201 lemma filter_true : ∀A,l,a,p. p a \ 5a title="leibnitz's equality" href="cic:/fakeuri.def(1)"\ 6=\ 5/a\ 6 \ 5a href="cic:/matita/basics/bool/bool.con(0,1,0)"\ 6true\ 5/a\ 6 → 
202   \ 5a href="cic:/matita/tutorial/chapter3/filter.def(2)"\ 6filter\ 5/a\ 6 A p (a\ 5a title="cons" href="cic:/fakeuri.def(1)"\ 6:\ 5/a\ 6:l) \ 5a title="leibnitz's equality" href="cic:/fakeuri.def(1)"\ 6=\ 5/a\ 6 a \ 5a title="cons" href="cic:/fakeuri.def(1)"\ 6:\ 5/a\ 6\ 5a href="cic:/matita/tutorial/chapter3/filter.def(2)"\ 6filter\ 5/a\ 6 A p l.
203 #A #l #a #p #pa (elim l) normalize >pa // qed.
204
205 lemma filter_false : ∀A,l,a,p. p a \ 5a title="leibnitz's equality" href="cic:/fakeuri.def(1)"\ 6=\ 5/a\ 6 \ 5a href="cic:/matita/basics/bool/bool.con(0,2,0)"\ 6false\ 5/a\ 6 → 
206   \ 5a href="cic:/matita/tutorial/chapter3/filter.def(2)"\ 6filter\ 5/a\ 6 A p (a\ 5a title="cons" href="cic:/fakeuri.def(1)"\ 6:\ 5/a\ 6:l) \ 5a title="leibnitz's equality" href="cic:/fakeuri.def(1)"\ 6=\ 5/a\ 6 \ 5a href="cic:/matita/tutorial/chapter3/filter.def(2)"\ 6filter\ 5/a\ 6 A p l.
207 #A #l #a #p #pa (elim l) normalize >pa normalize // qed.
208
209 (* As another example, let us redefine the map function using foldr. The
210 result type B is (list B), the base value b is [], and the fold function 
211 of type A → list B → list B is the function mapping a and l to (f a)::l.
212 *)
213
214 definition map_again ≝ λA,B,f,l. \ 5a href="cic:/matita/tutorial/chapter3/foldr.fix(0,4,1)"\ 6foldr\ 5/a\ 6 A (\ 5a href="cic:/matita/tutorial/chapter3/list.ind(1,0,1)"\ 6list\ 5/a\ 6 B) (λa,l.f a\ 5a title="cons" href="cic:/fakeuri.def(1)"\ 6:\ 5/a\ 6:l) \ 5a title="nil" href="cic:/fakeuri.def(1)"\ 6[\ 5/a\ 6] l.
215
216 (* Can we prove that map_again is "the same" as map? We should first of all
217 clarify in which sense we expect the two functions to be equal. Equality in
218 Matita has an intentional meaning: it is the smallest predicate induced by 
219 convertibility, i.e. syntactical equality up to normalization. From an 
220 intentional point of view, map and map_again are not functions, but programs,
221 and they are clearly different. What we would like to say is that the two
222 programs behave in the same way: this is a different, extensional equality 
223 that can be defined in the following way. *)
224
225 definition ExtEq ≝ λA,B:Type[0].λf,g:A→B.∀a:A.f a \ 5a title="leibnitz's equality" href="cic:/fakeuri.def(1)"\ 6=\ 5/a\ 6 g a.
226
227 (* Proving that map and map_again are extentionally equal in the 
228 previous sense can be proved by a trivial structural induction on the list *)
229
230 lemma eq_maps: ∀A,B,f. \ 5a href="cic:/matita/tutorial/chapter3/ExtEq.def(1)"\ 6ExtEq\ 5/a\ 6 ?? (\ 5a href="cic:/matita/tutorial/chapter3/map.fix(0,3,1)"\ 6map\ 5/a\ 6 A B f) (\ 5a href="cic:/matita/tutorial/chapter3/map_again.def(2)"\ 6map_again\ 5/a\ 6 A B f).
231 #A #B #f #n (elim n) normalize // qed. 
232
233 (* Let us make another remark about extensional equality. It is clear that,
234 if f is extensionally equal to g, then (map A B f) is extensionally equal to
235 (map A B g). Let us prove it. *)
236
237 theorem eq_map : ∀A,B,f,g. \ 5a href="cic:/matita/tutorial/chapter3/ExtEq.def(1)"\ 6ExtEq\ 5/a\ 6 A B f g → \ 5a href="cic:/matita/tutorial/chapter3/ExtEq.def(1)"\ 6ExtEq\ 5/a\ 6 ?? (\ 5a href="cic:/matita/tutorial/chapter3/map.fix(0,3,1)"\ 6map\ 5/a\ 6 \ 5span style="text-decoration: underline;"\ 6\ 5/span\ 6A B f) (\ 5a href="cic:/matita/tutorial/chapter3/map.fix(0,3,1)"\ 6map\ 5/a\ 6 A B g).
238 #A #B #f #g #eqfg
239  
240 (* the relevant point is that we cannot proceed by rewriting f with g via
241 eqfg, here. Rewriting only works with Matita intensional equality, while here
242 we are dealing with a different predicate, defined by the user. The right way 
243 to proceed is to unfold the definition of ExtEq, and work by induction on l, 
244 as usual when we want to prove extensional equality between functions over 
245 inductive types; again the rest of the proof is trivial. *)
246
247 #l (elim l) normalize // qed.
248
249 (**************************** BIGOPS *******************************)
250
251 (* Building a library of basic functions, it is important to achieve a 
252 good degree of abstraction and generality, in order to be able to reuse
253 suitable instances of the same function in different context. This has not
254 only the obvious benefit of factorizing code, but especially to avoid 
255 repeating proofs of generic properties over and over again.
256 A really convenient tool is the following combination of fold and filter,
257 that essentially allow you to iterate on every subset of a given enumerated
258 (finite) type, represented as a list. *) 
259
260  let rec fold (A,B:Type[0]) (op:B → B → B) (b:B) (p:A→\ 5a href="cic:/matita/basics/bool/bool.ind(1,0,0)" title="null"\ 6bool\ 5/a\ 6) (f:A→B) (l:\ 5a href="cic:/matita/tutorial/chapter3/list.ind(1,0,1)"\ 6list\ 5/a\ 6 A) on l :B ≝  
261  match l with 
262   [ nil ⇒ b 
263   | cons a l ⇒ \ 5a href="cic:/matita/basics/bool/if_then_else.def(1)"\ 6if_then_else\ 5/a\ 6 ? (p a) (op (f a) (fold A B op b p f l))
264       (fold A B op b p f l)].
265
266 (* It is also important to spend a few time to introduce some fancy notation
267 for these iterators. *)
268
269  notation "\fold  [ op , nil ]_{ ident i ∈ l | p} f"
270   with precedence 80
271 for @{'fold $op $nil (λ${ident i}. $p) (λ${ident i}. $f) $l}.
272
273 notation "\fold [ op , nil ]_{ident i ∈ l } f"
274   with precedence 80
275 for @{'fold $op $nil (λ${ident i}.true) (λ${ident i}. $f) $l}.
276
277 interpretation "\fold" 'fold op nil p f l = (fold ? ? op nil p f l).
278
279 theorem fold_true: 
280 ∀A,B.∀a:A.∀l.∀p.∀op:B→B→B.∀nil.∀f:A→B. p a \ 5a title="leibnitz's equality" href="cic:/fakeuri.def(1)"\ 6=\ 5/a\ 6 \ 5a href="cic:/matita/basics/bool/bool.con(0,1,0)"\ 6true\ 5/a\ 6 → 
281   \ 5a title="\fold" href="cic:/fakeuri.def(1)"\ 6\fold\ 5/a\ 6[op,nil]_{i ∈ a\ 5a title="cons" href="cic:/fakeuri.def(1)"\ 6:\ 5/a\ 6:l| p i} (f i) \ 5a title="leibnitz's equality" href="cic:/fakeuri.def(1)"\ 6=\ 5/a\ 6 
282     op (f a) \ 5a title="\fold" href="cic:/fakeuri.def(1)"\ 6\fold\ 5/a\ 6[op,nil]_{i ∈ l| p i} (f i). 
283 #A #B #a #l #p #op #nil #f #pa normalize >pa // qed.
284
285 theorem fold_false: 
286 ∀A,B.∀a:A.∀l.∀p.∀op:B→B→B.∀nil.∀f.
287 p a \ 5a title="leibnitz's equality" href="cic:/fakeuri.def(1)"\ 6=\ 5/a\ 6 \ 5a href="cic:/matita/basics/bool/bool.con(0,2,0)"\ 6false\ 5/a\ 6 → \ 5a title="\fold" href="cic:/fakeuri.def(1)"\ 6\fold\ 5/a\ 6[op,nil]_{i ∈ a\ 5a title="cons" href="cic:/fakeuri.def(1)"\ 6:\ 5/a\ 6:l| p i} (f i) \ 5a title="leibnitz's equality" href="cic:/fakeuri.def(1)"\ 6=\ 5/a\ 6 
288   \ 5a title="\fold" href="cic:/fakeuri.def(1)"\ 6\fold\ 5/a\ 6[op,nil]_{i ∈ l| p i} (f i).
289 #A #B #a #l #p #op #nil #f #pa normalize >pa // qed.
290
291 theorem fold_filter: 
292 ∀A,B.∀a:A.∀l.∀p.∀op:B→B→B.∀nil.∀f:A →B.
293   \ 5a title="\fold" href="cic:/fakeuri.def(1)"\ 6\fold\ 5/a\ 6[op,nil]_{i ∈ l| p i} (f i) \ 5a title="leibnitz's equality" href="cic:/fakeuri.def(1)"\ 6=\ 5/a\ 6 
294     \ 5a title="\fold" href="cic:/fakeuri.def(1)"\ 6\fold\ 5/a\ 6[op,nil]_{i ∈ (\ 5a href="cic:/matita/tutorial/chapter3/filter.def(2)"\ 6filter\ 5/a\ 6 A p l)} (f i).
295 #A #B #a #l #p #op #nil #f elim l //  
296 #a #tl #Hind cases(\ 5a href="cic:/matita/basics/bool/true_or_false.def(1)"\ 6true_or_false\ 5/a\ 6 (p a)) #pa 
297   [ >\ 5a href="cic:/matita/tutorial/chapter3/filter_true.def(3)"\ 6filter_true\ 5/a\ 6 // > \ 5a href="cic:/matita/tutorial/chapter3/fold_true.def(3)"\ 6fold_true\ 5/a\ 6 // >\ 5a href="cic:/matita/tutorial/chapter3/fold_true.def(3)"\ 6fold_true\ 5/a\ 6 //
298   | >\ 5a href="cic:/matita/tutorial/chapter3/filter_false.def(3)"\ 6filter_false\ 5/a\ 6 // >\ 5a href="cic:/matita/tutorial/chapter3/fold_false.def(3)"\ 6fold_false\ 5/a\ 6 // ]
299 qed.
300
301 record Aop (A:Type[0]) (nil:A) : Type[0] ≝
302 {op :2> A → A → A; 
303   nill:∀a. op nil a \ 5a title="leibnitz's equality" href="cic:/fakeuri.def(1)"\ 6=\ 5/a\ 6 a; 
304   nilr:∀a. op a nil \ 5a title="leibnitz's equality" href="cic:/fakeuri.def(1)"\ 6=\ 5/a\ 6 a;
305   assoc: ∀a,b,c.op a (op b c) \ 5a title="leibnitz's equality" href="cic:/fakeuri.def(1)"\ 6=\ 5/a\ 6 op (op a b) c
306 }.
307
308 theorem fold_sum: ∀A,B. ∀I,J:\ 5a href="cic:/matita/tutorial/chapter3/list.ind(1,0,1)"\ 6list\ 5/a\ 6 A.∀nil.∀op:\ 5a href="cic:/matita/tutorial/chapter3/Aop.ind(1,0,2)"\ 6Aop\ 5/a\ 6 B nil.∀f:A → B.
309  op (\ 5a title="\fold" href="cic:/fakeuri.def(1)"\ 6\fold\ 5/a\ 6[op,nil]_{i ∈ I} (f i)) (\ 5a title="\fold" href="cic:/fakeuri.def(1)"\ 6\fold\ 5/a\ 6[op,nil]_{i ∈ J} (f i)) \ 5a title="leibnitz's equality" href="cic:/fakeuri.def(1)"\ 6=\ 5/a\ 6 
310    \ 5a title="\fold" href="cic:/fakeuri.def(1)"\ 6\fold\ 5/a\ 6[op,nil]_{i ∈ (I\ 5a title="append" href="cic:/fakeuri.def(1)"\ 6@\ 5/a\ 6J)} (f i).
311 #A #B #I #J #nil #op #f (elim I) normalize 
312   [>\ 5a href="cic:/matita/tutorial/chapter3/nill.fix(0,2,2)"\ 6nill\ 5/a\ 6//|#a #tl #Hind <\ 5a href="cic:/matita/tutorial/chapter3/assoc.fix(0,2,2)"\ 6assoc\ 5/a\ 6 //]
313 qed.