list.bend
bend-mathlib@0.1.0.0 · 372 lines · 0 definitions
1import Base
2import bend-mathlib@0.1.0.0/nat.bend as MNat
3
4# The empty list is a right identity for append: xs ++ [] = xs.
5law append_nil:
6 for -a: Quant
7 for -A: Kind(a)
8 for xs: List<a, A>
9 {List.append(a, A, xs, Nil{}) == xs : List<a, A>}
10
11def append_nil(a, A, xs):
12 match xs:
13 case Nil{}:
14 {==}
15 case h <> t:
16 %append_nil(a, A, t) : {h <> List.append(a, A, t, Nil{}) == h <> _ : List<a, A>}
17 {==}
18
19# The empty list is a left identity for append: [] ++ xs = xs.
20law nil_append:
21 for -a: Quant
22 for -A: Kind(a)
23 for -xs: List<a, A>
24 {List.append(a, A, Nil{}, xs) == xs : List<a, A>}
25
26def nil_append(a, A, xs):
27 {==}
28
29# Append is associative: (xs ++ ys) ++ zs = xs ++ (ys ++ zs).
30law append_assoc:
31 for -a: Quant
32 for -A: Kind(a)
33 for xs: List<a, A>
34 for -ys: List<a, A>
35 for -zs: List<a, A>
36 {List.append(a, A, List.append(a, A, xs, ys), zs) == List.append(a, A, xs, List.append(a, A, ys, zs)) : List<a, A>}
37
38def append_assoc(a, A, xs, ys, zs):
39 match xs:
40 case Nil{}:
41 {==}
42 case h <> t:
43 %append_assoc(a, A, t, ys, zs) : {h <> List.append(a, A, List.append(a, A, t, ys), zs) == h <> _ : List<a, A>}
44 {==}
45
46# The length of an append is the sum of the lengths.
47law length_append:
48 for -a: Quant
49 for -A: Kind(a)
50 for xs: List<a, A>
51 for -ys: List<a, A>
52 {List.length(a, A, List.append(a, A, xs, ys)) == Nat.add(List.length(a, A, xs), List.length(a, A, ys)) : Nat}
53
54def length_append(a, A, xs, ys):
55 match xs:
56 case Nil{}:
57 {==}
58 case h <> t:
59 %length_append(a, A, t, ys) : {1n+List.length(a, A, List.append(a, A, t, ys)) == 1n+_ : Nat}
60 {==}
61
62def internal_reverse_go_append(a, -A: Kind(a), xs: List<a, A>, -ys: List<a, A>, -acc: List<a, A>) -> {List.reverse.go(a, A, xs, List.append(a, A, ys, acc)) == List.append(a, A, List.reverse.go(a, A, xs, ys), acc) : List<a, A>}:
63 match xs:
64 case Nil{}:
65 {==}
66 case h <> t:
67 internal_reverse_go_append(a, A, t, h <> ys, acc)
68
69# The reverse accumulator loop appends the reversed list to the accumulator.
70law reverse_go_spec:
71 for -a: Quant
72 for -A: Kind(a)
73 for xs: List<a, A>
74 for -acc: List<a, A>
75 {List.reverse.go(a, A, xs, acc) == List.append(a, A, List.reverse(a, A, xs), acc) : List<a, A>}
76
77def reverse_go_spec(a, A, xs, acc):
78 match xs:
79 case Nil{}:
80 {==}
81 case h <> t:
82 internal_reverse_go_append(a, A, t, h <> Nil{}, acc)
83
84def internal_reverse_append_go(a, -A: Kind(a), xs: List<a, A>, -ys: List<a, A>, -acc: List<a, A>) -> {List.reverse.go(a, A, List.append(a, A, xs, ys), acc) == List.reverse.go(a, A, ys, List.reverse.go(a, A, xs, acc)) : List<a, A>}:
85 match xs:
86 case Nil{}:
87 {==}
88 case h <> t:
89 internal_reverse_append_go(a, A, t, ys, h <> acc)
90
91# Reversing an append reverses and swaps the parts: reverse (xs ++ ys) = reverse ys ++ reverse xs.
92law reverse_append:
93 for -a: Quant
94 for -A: Kind(a)
95 for xs: List<a, A>
96 for ys: List<a, A>
97 {List.reverse(a, A, List.append(a, A, xs, ys)) == List.append(a, A, List.reverse(a, A, ys), List.reverse(a, A, xs)) : List<a, A>}
98
99def reverse_append(a, A, xs, ys):
100 Equal.trans(List<a, A>, List.reverse(a, A, List.append(a, A, xs, ys)), List.reverse.go(a, A, ys, List.reverse(a, A, xs)), List.append(a, A, List.reverse(a, A, ys), List.reverse(a, A, xs)), internal_reverse_append_go(a, A, xs, ys, Nil{}), reverse_go_spec(a, A, ys, List.reverse(a, A, xs)))
101
102def internal_reverse_go_go(a, -A: Kind(a), xs: List<a, A>, -acc: List<a, A>) -> {List.reverse.go(a, A, List.reverse.go(a, A, xs, acc), Nil{}) == List.reverse.go(a, A, acc, xs) : List<a, A>}:
103 match xs:
104 case Nil{}:
105 {==}
106 case h <> t:
107 internal_reverse_go_go(a, A, t, h <> acc)
108
109# Reversing twice gives the list back.
110law reverse_reverse:
111 for -a: Quant
112 for -A: Kind(a)
113 for xs: List<a, A>
114 {List.reverse(a, A, List.reverse(a, A, xs)) == xs : List<a, A>}
115
116def reverse_reverse(a, A, xs):
117 internal_reverse_go_go(a, A, xs, Nil{})
118
119def internal_length_reverse_go(a, -A: Kind(a), xs: List<a, A>, -acc: List<a, A>, +n: Nat, e: {List.length(a, A, acc) == n : Nat}) -> {List.length(a, A, List.reverse.go(a, A, xs, acc)) == Nat.add(n, List.length(a, A, xs)) : Nat}:
120 match xs:
121 case Nil{}:
122 %Equal.sym(Nat, Nat.add(n, 0n), n, MNat.add_zero(n)) : {List.length(a, A, acc) == _ : Nat}
123 e
124 case h <> t:
125 %Equal.sym(Nat, Nat.add(n, 1n+List.length(a, A, t)), 1n+Nat.add(n, List.length(a, A, t)), MNat.add_succ(n, List.length(a, A, t))) : {List.length(a, A, List.reverse.go(a, A, t, h <> acc)) == _ : Nat}
126 internal_length_reverse_go(a, A, t, h <> acc, 1n+n, Equal.cong(Nat, Nat, k => 1n+k, List.length(a, A, acc), n, e))
127
128# Reversing preserves the length.
129law length_reverse:
130 for -a: Quant
131 for -A: Kind(a)
132 for xs: List<a, A>
133 {List.length(a, A, List.reverse(a, A, xs)) == List.length(a, A, xs) : Nat}
134
135def length_reverse(a, A, xs):
136 internal_length_reverse_go(a, A, xs, Nil{}, 0n, {==})
137
138# A right fold over an append folds the first part onto the fold of the second.
139law foldr_append:
140 for ~a: Quant
141 for ~A: Kind(a)
142 for ~B: Type
143 for ~f: A -> B -> B
144 for xs: List<a, A>
145 for -ys: List<a, A>
146 for -z: B
147 {List.foldr(~a, ~A, ~B, ~f, List.append(a, A, xs, ys), z) == List.foldr(~a, ~A, ~B, ~f, xs, List.foldr(~a, ~A, ~B, ~f, ys, z)) : B}
148
149def foldr_append(a, A, B, f, xs, ys, z):
150 match xs:
151 case Nil{}:
152 {==}
153 case h <> t:
154 %foldr_append(~a, ~A, ~B, ~f, t, ys, z) : {f(h, List.foldr(~a, ~A, ~B, ~f, List.append(a, A, t, ys), z)) == f(h, _) : B}
155 {==}
156
157# Taking n elements and appending the rest after dropping n gives the list back.
158law take_append_drop:
159 for -a: Quant
160 for -A: Kind(a)
161 for xs: List<a, A>
162 for n: Nat
163 {List.append(a, A, List.take(a, A, xs, n), List.drop(a, A, xs, n)) == xs : List<a, A>}
164
165def take_append_drop(a, A, xs, n):
166 match xs n:
167 case Nil{} _:
168 {==}
169 case h <> t 0n:
170 {==}
171 case h <> t 1n+p:
172 %take_append_drop(a, A, t, p) : {h <> List.append(a, A, List.take(a, A, t, p), List.drop(a, A, t, p)) == h <> _ : List<a, A>}
173 {==}
174
175# Mapping preserves the length.
176law length_map:
177 for ~A: Type
178 for ~B: Type
179 for ~f: A -> B
180 for xs: List<A>
181 {List.length(&1, B, List.map(~A, ~B, ~f, xs)) == List.length(&1, A, xs) : Nat}
182
183def length_map(A, B, f, xs):
184 match xs:
185 case Nil{}:
186 {==}
187 case h <> t:
188 %length_map(~A, ~B, ~f, t) : {1n+List.length(&1, B, List.map(~A, ~B, ~f, t)) == 1n+_ : Nat}
189 {==}
190
191# Mapping over an append maps each part: map f (xs ++ ys) = map f xs ++ map f ys.
192law map_append:
193 for ~A: Type
194 for ~B: Type
195 for ~f: A -> B
196 for xs: List<A>
197 for -ys: List<A>
198 {List.map(~A, ~B, ~f, List.append(&1, A, xs, ys)) == List.append(&1, B, List.map(~A, ~B, ~f, xs), List.map(~A, ~B, ~f, ys)) : List<B>}
199
200def map_append(A, B, f, xs, ys):
201 match xs:
202 case Nil{}:
203 {==}
204 case h <> t:
205 %map_append(~A, ~B, ~f, t, ys) : {f(h) <> List.map(~A, ~B, ~f, List.append(&1, A, t, ys)) == f(h) <> _ : List<B>}
206 {==}
207
208# Mapping twice is mapping the composition: map g (map f xs) = map (g . f) xs.
209law map_map:
210 for ~A: Type
211 for ~B: Type
212 for ~C: Type
213 for ~f: A -> B
214 for ~g: B -> C
215 for xs: List<A>
216 {List.map(~B, ~C, ~g, List.map(~A, ~B, ~f, xs)) == List.map(~A, ~C, ~(x => g(f(x))), xs) : List<C>}
217
218def map_map(A, B, C, f, g, xs):
219 match xs:
220 case Nil{}:
221 {==}
222 case h <> t:
223 %map_map(~A, ~B, ~C, ~f, ~g, t) : {g(f(h)) <> List.map(~B, ~C, ~g, List.map(~A, ~B, ~f, t)) == g(f(h)) <> _ : List<C>}
224 {==}
225
226# --- generated: _sym twins (tools/mathlib/twins.ts), do not edit ---
227
228# The empty list is a right identity for append: xs ++ [] = xs, reversed to rewrite toward the simple side.
229law append_nil_sym:
230 for -a: Quant
231 for -A: Kind(a)
232 for xs: List<a, A>
233 {xs == List.append(a, A, xs, Nil{}) : List<a, A>}
234
235def append_nil_sym(a, A, xs):
236 Equal.sym(List<a, A>, List.append(a, A, xs, Nil{}), xs, append_nil(a, A, xs))
237
238# The empty list is a left identity for append: [] ++ xs = xs, reversed to rewrite toward the simple side.
239law nil_append_sym:
240 for -a: Quant
241 for -A: Kind(a)
242 for -xs: List<a, A>
243 {xs == List.append(a, A, Nil{}, xs) : List<a, A>}
244
245def nil_append_sym(a, A, xs):
246 Equal.sym(List<a, A>, List.append(a, A, Nil{}, xs), xs, nil_append(a, A, xs))
247
248# Append is associative: (xs ++ ys) ++ zs = xs ++ (ys ++ zs), reversed to rewrite toward the simple side.
249law append_assoc_sym:
250 for -a: Quant
251 for -A: Kind(a)
252 for xs: List<a, A>
253 for -ys: List<a, A>
254 for -zs: List<a, A>
255 {List.append(a, A, xs, List.append(a, A, ys, zs)) == List.append(a, A, List.append(a, A, xs, ys), zs) : List<a, A>}
256
257def append_assoc_sym(a, A, xs, ys, zs):
258 Equal.sym(List<a, A>, List.append(a, A, List.append(a, A, xs, ys), zs), List.append(a, A, xs, List.append(a, A, ys, zs)), append_assoc(a, A, xs, ys, zs))
259
260# The length of an append is the sum of the lengths, reversed to rewrite toward the simple side.
261law length_append_sym:
262 for -a: Quant
263 for -A: Kind(a)
264 for xs: List<a, A>
265 for -ys: List<a, A>
266 {Nat.add(List.length(a, A, xs), List.length(a, A, ys)) == List.length(a, A, List.append(a, A, xs, ys)) : Nat}
267
268def length_append_sym(a, A, xs, ys):
269 Equal.sym(Nat, List.length(a, A, List.append(a, A, xs, ys)), Nat.add(List.length(a, A, xs), List.length(a, A, ys)), length_append(a, A, xs, ys))
270
271# The reverse accumulator loop appends the reversed list to the accumulator, reversed to rewrite toward the simple side.
272law reverse_go_spec_sym:
273 for -a: Quant
274 for -A: Kind(a)
275 for xs: List<a, A>
276 for -acc: List<a, A>
277 {List.append(a, A, List.reverse(a, A, xs), acc) == List.reverse.go(a, A, xs, acc) : List<a, A>}
278
279def reverse_go_spec_sym(a, A, xs, acc):
280 Equal.sym(List<a, A>, List.reverse.go(a, A, xs, acc), List.append(a, A, List.reverse(a, A, xs), acc), reverse_go_spec(a, A, xs, acc))
281
282# Reversing an append reverses and swaps the parts: reverse (xs ++ ys) = reverse ys ++ reverse xs, reversed to rewrite toward the simple side.
283law reverse_append_sym:
284 for -a: Quant
285 for -A: Kind(a)
286 for xs: List<a, A>
287 for ys: List<a, A>
288 {List.append(a, A, List.reverse(a, A, ys), List.reverse(a, A, xs)) == List.reverse(a, A, List.append(a, A, xs, ys)) : List<a, A>}
289
290def reverse_append_sym(a, A, xs, ys):
291 Equal.sym(List<a, A>, List.reverse(a, A, List.append(a, A, xs, ys)), List.append(a, A, List.reverse(a, A, ys), List.reverse(a, A, xs)), reverse_append(a, A, xs, ys))
292
293# Reversing twice gives the list back, reversed to rewrite toward the simple side.
294law reverse_reverse_sym:
295 for -a: Quant
296 for -A: Kind(a)
297 for xs: List<a, A>
298 {xs == List.reverse(a, A, List.reverse(a, A, xs)) : List<a, A>}
299
300def reverse_reverse_sym(a, A, xs):
301 Equal.sym(List<a, A>, List.reverse(a, A, List.reverse(a, A, xs)), xs, reverse_reverse(a, A, xs))
302
303# Reversing preserves the length, reversed to rewrite toward the simple side.
304law length_reverse_sym:
305 for -a: Quant
306 for -A: Kind(a)
307 for xs: List<a, A>
308 {List.length(a, A, xs) == List.length(a, A, List.reverse(a, A, xs)) : Nat}
309
310def length_reverse_sym(a, A, xs):
311 Equal.sym(Nat, List.length(a, A, List.reverse(a, A, xs)), List.length(a, A, xs), length_reverse(a, A, xs))
312
313# A right fold over an append folds the first part onto the fold of the second, reversed to rewrite toward the simple side.
314law foldr_append_sym:
315 for ~a: Quant
316 for ~A: Kind(a)
317 for ~B: Type
318 for ~f: A -> B -> B
319 for xs: List<a, A>
320 for -ys: List<a, A>
321 for -z: B
322 {List.foldr(~a, ~A, ~B, ~f, xs, List.foldr(~a, ~A, ~B, ~f, ys, z)) == List.foldr(~a, ~A, ~B, ~f, List.append(a, A, xs, ys), z) : B}
323
324def foldr_append_sym(a, A, B, f, xs, ys, z):
325 Equal.sym(B, List.foldr(~a, ~A, ~B, ~f, List.append(a, A, xs, ys), z), List.foldr(~a, ~A, ~B, ~f, xs, List.foldr(~a, ~A, ~B, ~f, ys, z)), foldr_append(~a, ~A, ~B, ~f, xs, ys, z))
326
327# Taking n elements and appending the rest after dropping n gives the list back, reversed to rewrite toward the simple side.
328law take_append_drop_sym:
329 for -a: Quant
330 for -A: Kind(a)
331 for xs: List<a, A>
332 for n: Nat
333 {xs == List.append(a, A, List.take(a, A, xs, n), List.drop(a, A, xs, n)) : List<a, A>}
334
335def take_append_drop_sym(a, A, xs, n):
336 Equal.sym(List<a, A>, List.append(a, A, List.take(a, A, xs, n), List.drop(a, A, xs, n)), xs, take_append_drop(a, A, xs, n))
337
338# Mapping preserves the length, reversed to rewrite toward the simple side.
339law length_map_sym:
340 for ~A: Type
341 for ~B: Type
342 for ~f: A -> B
343 for xs: List<A>
344 {List.length(&1, A, xs) == List.length(&1, B, List.map(~A, ~B, ~f, xs)) : Nat}
345
346def length_map_sym(A, B, f, xs):
347 Equal.sym(Nat, List.length(&1, B, List.map(~A, ~B, ~f, xs)), List.length(&1, A, xs), length_map(~A, ~B, ~f, xs))
348
349# Mapping over an append maps each part: map f (xs ++ ys) = map f xs ++ map f ys, reversed to rewrite toward the simple side.
350law map_append_sym:
351 for ~A: Type
352 for ~B: Type
353 for ~f: A -> B
354 for xs: List<A>
355 for -ys: List<A>
356 {List.append(&1, B, List.map(~A, ~B, ~f, xs), List.map(~A, ~B, ~f, ys)) == List.map(~A, ~B, ~f, List.append(&1, A, xs, ys)) : List<B>}
357
358def map_append_sym(A, B, f, xs, ys):
359 Equal.sym(List<B>, List.map(~A, ~B, ~f, List.append(&1, A, xs, ys)), List.append(&1, B, List.map(~A, ~B, ~f, xs), List.map(~A, ~B, ~f, ys)), map_append(~A, ~B, ~f, xs, ys))
360
361# Mapping twice is mapping the composition: map g (map f xs) = map (g . f) xs, reversed to rewrite toward the simple side.
362law map_map_sym:
363 for ~A: Type
364 for ~B: Type
365 for ~C: Type
366 for ~f: A -> B
367 for ~g: B -> C
368 for xs: List<A>
369 {List.map(~A, ~C, ~(x => g(f(x))), xs) == List.map(~B, ~C, ~g, List.map(~A, ~B, ~f, xs)) : List<C>}
370
371def map_map_sym(A, B, C, f, g, xs):
372 Equal.sym(List<C>, List.map(~B, ~C, ~g, List.map(~A, ~B, ~f, xs)), List.map(~A, ~C, ~(x => g(f(x))), xs), map_map(~A, ~B, ~C, ~f, ~g, xs))