1 # bend-mathlib/list.bend: List lemmas (append, reverse, length, take, drop, map, fold, filter).
2 import Base
3 import ./nat.bend as MNat
4 import ./bool.bend as MBool
5
6 # The empty list is a right identity for append: xs ++ [] = xs.
7 law append_nil:
8 for -a: Quant
9 for -A: Kind(a)
10 for xs: List
11 {List.append(a, A, xs, Nil{}) == xs : List}
12
13 def append_nil(a, A, xs):
14 match xs:
15 case Nil{}:
16 {==}
17 case h <> t:
18 %append_nil(a, A, t) : {h <> List.append(a, A, t, Nil{}) == h <> _ : List}
19 {==}
20
21 # The empty list is a left identity for append: [] ++ xs = xs.
22 law nil_append:
23 for -a: Quant
24 for -A: Kind(a)
25 for -xs: List
26 {List.append(a, A, Nil{}, xs) == xs : List}
27
28 def nil_append(a, A, xs):
29 {==}
30
31 # Append is associative: (xs ++ ys) ++ zs = xs ++ (ys ++ zs).
32 law append_assoc:
33 for -a: Quant
34 for -A: Kind(a)
35 for xs: List
36 for -ys: List
37 for -zs: List
38 {List.append(a, A, List.append(a, A, xs, ys), zs) == List.append(a, A, xs, List.append(a, A, ys, zs)) : List}
39
40 def append_assoc(a, A, xs, ys, zs):
41 match xs:
42 case Nil{}:
43 {==}
44 case h <> t:
45 %append_assoc(a, A, t, ys, zs) : {h <> List.append(a, A, List.append(a, A, t, ys), zs) == h <> _ : List}
46 {==}
47
48 # The length of an append is the sum of the lengths.
49 law length_append:
50 for -a: Quant
51 for -A: Kind(a)
52 for xs: List
53 for -ys: List
54 {List.length(a, A, List.append(a, A, xs, ys)) == Nat.add(List.length(a, A, xs), List.length(a, A, ys)) : Nat}
55
56 def length_append(a, A, xs, ys):
57 match xs:
58 case Nil{}:
59 {==}
60 case h <> t:
61 %length_append(a, A, t, ys) : {1n+List.length(a, A, List.append(a, A, t, ys)) == 1n+_ : Nat}
62 {==}
63
64 def internal_reverse_go_append(a, -A: Kind(a), xs: List, -ys: List, -acc: List) -> {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}:
65 match xs:
66 case Nil{}:
67 {==}
68 case h <> t:
69 internal_reverse_go_append(a, A, t, h <> ys, acc)
70
71 # The reverse accumulator loop appends the reversed list to the accumulator.
72 law reverse_go_spec:
73 for -a: Quant
74 for -A: Kind(a)
75 for xs: List
76 for -acc: List
77 {List.reverse.go(a, A, xs, acc) == List.append(a, A, List.reverse(a, A, xs), acc) : List}
78
79 def reverse_go_spec(a, A, xs, acc):
80 match xs:
81 case Nil{}:
82 {==}
83 case h <> t:
84 internal_reverse_go_append(a, A, t, h <> Nil{}, acc)
85
86 def internal_reverse_append_go(a, -A: Kind(a), xs: List, -ys: List, -acc: List) -> {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}:
87 match xs:
88 case Nil{}:
89 {==}
90 case h <> t:
91 internal_reverse_append_go(a, A, t, ys, h <> acc)
92
93 # Reversing an append reverses and swaps the parts: reverse (xs ++ ys) = reverse ys ++ reverse xs.
94 law reverse_append:
95 for -a: Quant
96 for -A: Kind(a)
97 for xs: List
98 for ys: List
99 {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}
100
101 def reverse_append(a, A, xs, ys):
102 Equal.trans(List, 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)))
103
104 def internal_reverse_go_go(a, -A: Kind(a), xs: List, -acc: List) -> {List.reverse.go(a, A, List.reverse.go(a, A, xs, acc), Nil{}) == List.reverse.go(a, A, acc, xs) : List}:
105 match xs:
106 case Nil{}:
107 {==}
108 case h <> t:
109 internal_reverse_go_go(a, A, t, h <> acc)
110
111 # Reversing twice gives the list back.
112 law reverse_reverse:
113 for -a: Quant
114 for -A: Kind(a)
115 for xs: List
116 {List.reverse(a, A, List.reverse(a, A, xs)) == xs : List}
117
118 def reverse_reverse(a, A, xs):
119 internal_reverse_go_go(a, A, xs, Nil{})
120
121 def internal_length_reverse_go(a, -A: Kind(a), xs: List, -acc: List, +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}:
122 match xs:
123 case Nil{}:
124 %Equal.sym(Nat, Nat.add(n, 0n), n, MNat.add_zero(n)) : {List.length(a, A, acc) == _ : Nat}
125 e
126 case h <> t:
127 %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}
128 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))
129
130 # Reversing preserves the length.
131 law length_reverse:
132 for -a: Quant
133 for -A: Kind(a)
134 for xs: List
135 {List.length(a, A, List.reverse(a, A, xs)) == List.length(a, A, xs) : Nat}
136
137 def length_reverse(a, A, xs):
138 internal_length_reverse_go(a, A, xs, Nil{}, 0n, {==})
139
140 # A right fold over an append folds the first part onto the fold of the second.
141 law foldr_append:
142 for ~a: Quant
143 for ~A: Kind(a)
144 for ~B: Type
145 for ~f: A -> B -> B
146 for xs: List
147 for -ys: List
148 for -z: B
149 {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}
150
151 def foldr_append(a, A, B, f, xs, ys, z):
152 match xs:
153 case Nil{}:
154 {==}
155 case h <> t:
156 %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}
157 {==}
158
159 # Taking n elements and appending the rest after dropping n gives the list back.
160 law take_append_drop:
161 for -a: Quant
162 for -A: Kind(a)
163 for xs: List
164 for n: Nat
165 {List.append(a, A, List.take(a, A, xs, n), List.drop(a, A, xs, n)) == xs : List}
166
167 def take_append_drop(a, A, xs, n):
168 match xs n:
169 case Nil{} _:
170 {==}
171 case h <> t 0n:
172 {==}
173 case h <> t 1n+p:
174 %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}
175 {==}
176
177 # Mapping preserves the length.
178 law length_map:
179 for ~A: Type
180 for ~B: Type
181 for ~f: A -> B
182 for xs: List
183 {List.length(&1, B, List.map(~A, ~B, ~f, xs)) == List.length(&1, A, xs) : Nat}
184
185 def length_map(A, B, f, xs):
186 match xs:
187 case Nil{}:
188 {==}
189 case h <> t:
190 %length_map(~A, ~B, ~f, t) : {1n+List.length(&1, B, List.map(~A, ~B, ~f, t)) == 1n+_ : Nat}
191 {==}
192
193 # Mapping over an append maps each part: map f (xs ++ ys) = map f xs ++ map f ys.
194 law map_append:
195 for ~A: Type
196 for ~B: Type
197 for ~f: A -> B
198 for xs: List
199 for -ys: List
200 {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}
201
202 def map_append(A, B, f, xs, ys):
203 match xs:
204 case Nil{}:
205 {==}
206 case h <> t:
207 %map_append(~A, ~B, ~f, t, ys) : {f(h) <> List.map(~A, ~B, ~f, List.append(&1, A, t, ys)) == f(h) <> _ : List}
208 {==}
209
210 # Mapping twice is mapping the composition: map g (map f xs) = map (g . f) xs.
211 law map_map:
212 for ~A: Type
213 for ~B: Type
214 for ~C: Type
215 for ~f: A -> B
216 for ~g: B -> C
217 for xs: List
218 {List.map(~B, ~C, ~g, List.map(~A, ~B, ~f, xs)) == List.map(~A, ~C, ~(x => g(f(x))), xs) : List}
219
220 def map_map(A, B, C, f, g, xs):
221 match xs:
222 case Nil{}:
223 {==}
224 case h <> t:
225 %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}
226 {==}
227
228 # Taking zero elements gives the empty list.
229 law take_zero:
230 for -a: Quant
231 for -A: Kind(a)
232 for xs: List
233 {List.take(a, A, xs, 0n) == Nil{} : List}
234
235 def take_zero(a, A, xs):
236 match xs:
237 case Nil{}:
238 {==}
239 case h <> t:
240 {==}
241
242 # Dropping zero elements gives the list back.
243 law drop_zero:
244 for -a: Quant
245 for -A: Kind(a)
246 for xs: List
247 {List.drop(a, A, xs, 0n) == xs : List}
248
249 def drop_zero(a, A, xs):
250 match xs:
251 case Nil{}:
252 {==}
253 case h <> t:
254 {==}
255
256 # Taking from the empty list gives the empty list.
257 law take_nil:
258 for -a: Quant
259 for -A: Kind(a)
260 for -n: Nat
261 {List.take(a, A, Nil{}, n) == Nil{} : List}
262
263 def take_nil(a, A, n):
264 {==}
265
266 # Dropping from the empty list gives the empty list.
267 law drop_nil:
268 for -a: Quant
269 for -A: Kind(a)
270 for -n: Nat
271 {List.drop(a, A, Nil{}, n) == Nil{} : List}
272
273 def drop_nil(a, A, n):
274 {==}
275
276 # Taking n elements leaves min(n, length) of them.
277 law length_take:
278 for -a: Quant
279 for -A: Kind(a)
280 for xs: List
281 for n: Nat
282 {List.length(a, A, List.take(a, A, xs, n)) == Nat.min(n, List.length(a, A, xs)) : Nat}
283
284 def length_take(a, A, xs, n):
285 match xs n:
286 case Nil{} _:
287 Equal.sym(Nat, Nat.min(n, 0n), 0n, MNat.min_zero(n))
288 case h <> t 0n:
289 {==}
290 case h <> t 1n+p:
291 %length_take(a, A, t, p) : {1n+List.length(a, A, List.take(a, A, t, p)) == 1n+_ : Nat}
292 {==}
293
294 # Dropping n elements leaves length - n of them.
295 law length_drop:
296 for -a: Quant
297 for -A: Kind(a)
298 for xs: List
299 for n: Nat
300 {List.length(a, A, List.drop(a, A, xs, n)) == Nat.sub(List.length(a, A, xs), n) : Nat}
301
302 def length_drop(a, A, xs, n):
303 match xs n:
304 case Nil{} _:
305 Equal.sym(Nat, Nat.sub(0n, n), 0n, MNat.zero_sub(n))
306 case h <> t 0n:
307 {==}
308 case h <> t 1n+p:
309 length_drop(a, A, t, p)
310
311 # Taking as many elements as the list has gives the list back.
312 law take_length:
313 for -A: Data
314 for +xs: List<&2, A>
315 {List.take(&2, A, xs, List.length(&2, A, xs)) == xs : List<&2, A>}
316
317 def take_length(A, xs):
318 match xs:
319 case Nil{}:
320 {==}
321 case h <> t:
322 %take_length(A, t) : {h <> List.take(&2, A, t, List.length(&2, A, t)) == h <> _ : List<&2, A>}
323 {==}
324
325 # Dropping as many elements as the list has gives the empty list.
326 law drop_length:
327 for -A: Data
328 for +xs: List<&2, A>
329 {List.drop(&2, A, xs, List.length(&2, A, xs)) == Nil{} : List<&2, A>}
330
331 def drop_length(A, xs):
332 match xs:
333 case Nil{}:
334 {==}
335 case h <> t:
336 drop_length(A, t)
337
338 # Taking m from the first n is taking min(n, m).
339 law take_take:
340 for -a: Quant
341 for -A: Kind(a)
342 for xs: List
343 for n: Nat
344 for m: Nat
345 {List.take(a, A, List.take(a, A, xs, n), m) == List.take(a, A, xs, Nat.min(n, m)) : List}
346
347 def take_take(a, A, xs, n, m):
348 match xs n m:
349 case Nil{} _ _:
350 {==}
351 case h <> t 0n _:
352 {==}
353 case h <> t 1n+p 0n:
354 {==}
355 case h <> t 1n+p 1n+q:
356 %take_take(a, A, t, p, q) : {h <> List.take(a, A, List.take(a, A, t, p), q) == h <> _ : List}
357 {==}
358
359 # Dropping m after dropping n is dropping n + m.
360 law drop_drop:
361 for -a: Quant
362 for -A: Kind(a)
363 for xs: List
364 for n: Nat
365 for -m: Nat
366 {List.drop(a, A, List.drop(a, A, xs, n), m) == List.drop(a, A, xs, Nat.add(n, m)) : List}
367
368 def drop_drop(a, A, xs, n, m):
369 match xs n m:
370 case Nil{} _ _:
371 {==}
372 case h <> t 0n _:
373 {==}
374 case h <> t 1n+p _:
375 drop_drop(a, A, t, p, m)
376
377 # Reversing the empty list gives the empty list.
378 law reverse_nil:
379 for -a: Quant
380 for -A: Kind(a)
381 {List.reverse(a, A, Nil{}) == Nil{} : List}
382
383 def reverse_nil(a, A):
384 {==}
385
386 # Reversing a one-element list gives it back.
387 law reverse_singleton:
388 for -a: Quant
389 for -A: Kind(a)
390 for -x: A
391 {List.reverse(a, A, [x]) == [x] : List}
392
393 def reverse_singleton(a, A, x):
394 {==}
395
396 # Replicating x n times gives a list of length n.
397 law length_replicate:
398 for -A: Data
399 for n: Nat
400 for -x: A
401 {List.length(&2, A, List.replicate(A, n, x)) == n : Nat}
402
403 def length_replicate(A, n, x):
404 match n:
405 case 0n:
406 {==}
407 case 1n+p:
408 %length_replicate(A, p, x) : {1n+List.length(&2, A, List.replicate(A, p, x)) == 1n+_ : Nat}
409 {==}
410
411 # Range(n) has length n.
412 law length_range:
413 for n: Nat
414 {List.length(&2, Nat, List.range(n)) == n : Nat}
415
416 def internal_length_range_go(+n: Nat, acc: List<&2, Nat>) -> {List.length(&2, Nat, List.range.go(n, acc)) == Nat.add(n, List.length(&2, Nat, acc)) : Nat}:
417 match n:
418 case 0n:
419 {==}
420 case 1n+p:
421 %MNat.add_succ(p, List.length(&2, Nat, acc)) : {List.length(&2, Nat, List.range.go(p, p <> acc)) == _ : Nat}
422 internal_length_range_go(p, p <> acc)
423
424 def length_range(n):
425 +n = n
426 %Equal.sym(Nat, List.length(&2, Nat, List.range.go(n, Nil{})), Nat.add(n, 0n), internal_length_range_go(n, Nil{})) : {_ == n : Nat}
427 MNat.add_zero(n)
428
429 # Zipping two lists gives the length of the shorter one.
430 law length_zip:
431 for -a: Quant
432 for -A: Kind(a)
433 for xs: List
434 for ys: List
435 {List.length(&1, A & A, List.zip(a, A, a, A, xs, ys)) == Nat.min(List.length(a, A, xs), List.length(a, A, ys)) : Nat}
436
437 def length_zip(a, A, xs, ys):
438 match xs ys:
439 case Nil{} _:
440 {==}
441 case h <> t Nil{}:
442 {==}
443 case h <> t y <> yt:
444 %length_zip(a, A, t, yt) : {1n+List.length(&1, A & A, List.zip(a, A, a, A, t, yt)) == 1n+_ : Nat}
445 {==}
446
447 # Appending after a cons: (x :: xs) ++ ys = x :: (xs ++ ys).
448 law append_cons:
449 for -a: Quant
450 for -A: Kind(a)
451 for -x: A
452 for -xs: List
453 for -ys: List
454 {List.append(a, A, x <> xs, ys) == x <> List.append(a, A, xs, ys) : List}
455
456 def append_cons(a, A, x, xs, ys):
457 {==}
458
459 # The empty list has length zero.
460 law length_nil:
461 for -a: Quant
462 for -A: Kind(a)
463 {List.length(a, A, Nil{}) == 0n : Nat}
464
465 def length_nil(a, A):
466 {==}
467
468 # A cons is one longer than its tail.
469 law length_cons:
470 for -a: Quant
471 for -A: Kind(a)
472 for -x: A
473 for -xs: List
474 {List.length(a, A, x <> xs) == 1n+List.length(a, A, xs) : Nat}
475
476 def length_cons(a, A, x, xs):
477 {==}
478
479 # Concatenating an append concatenates each part: concat (xss ++ yss) = concat xss ++ concat yss.
480 law concat_append:
481 for -a: Quant
482 for -A: Kind(a)
483 for xss: List>
484 for -yss: List>
485 {List.concat(a, A, List.append(a, List, xss, yss)) == List.append(a, A, List.concat(a, A, xss), List.concat(a, A, yss)) : List}
486
487 def concat_append(a, A, xss, yss):
488 match xss:
489 case Nil{}:
490 {==}
491 case h <> t:
492 %Equal.sym(List, List.concat(a, A, List.append(a, List, t, yss)), List.append(a, A, List.concat(a, A, t), List.concat(a, A, yss)), concat_append(a, A, t, yss)) : {List.append(a, A, h, _) == List.append(a, A, List.append(a, A, h, List.concat(a, A, t)), List.concat(a, A, yss)) : List}
493 Equal.sym(List, List.append(a, A, List.append(a, A, h, List.concat(a, A, t)), List.concat(a, A, yss)), List.append(a, A, h, List.append(a, A, List.concat(a, A, t), List.concat(a, A, yss))), append_assoc(a, A, h, List.concat(a, A, t), List.concat(a, A, yss)))
494
495 # A left fold over an append folds the second part from the fold of the first.
496 law foldl_append:
497 for ~a: Quant
498 for ~A: Kind(a)
499 for ~B: Type
500 for ~f: B -> A -> B
501 for xs: List
502 for -ys: List
503 for -z: B
504 {List.foldl(~a, ~A, ~B, ~f, List.append(a, A, xs, ys), z) == List.foldl(~a, ~A, ~B, ~f, ys, List.foldl(~a, ~A, ~B, ~f, xs, z)) : B}
505
506 def foldl_append(a, A, B, f, xs, ys, z):
507 match xs:
508 case Nil{}:
509 {==}
510 case h <> t:
511 foldl_append(~a, ~A, ~B, ~f, t, ys, f(z, h))
512
513 # Mapping commutes with reversing: map f (reverse xs) = reverse (map f xs).
514 law map_reverse:
515 for ~A: Type
516 for ~B: Type
517 for ~f: A -> B
518 for xs: List
519 {List.map(~A, ~B, ~f, List.reverse(&1, A, xs)) == List.reverse(&1, B, List.map(~A, ~B, ~f, xs)) : List}
520
521 def internal_map_reverse_go(~A: Type, ~B: Type, ~f: A -> B, xs: List, acc: List) -> {List.map(~A, ~B, ~f, List.reverse.go(&1, A, xs, acc)) == List.reverse.go(&1, B, List.map(~A, ~B, ~f, xs), List.map(~A, ~B, ~f, acc)) : List}:
522 match xs:
523 case Nil{}:
524 {==}
525 case h <> t:
526 internal_map_reverse_go(~A, ~B, ~f, t, h <> acc)
527
528 def map_reverse(A, B, f, xs):
529 internal_map_reverse_go(~A, ~B, ~f, xs, Nil{})
530
531 # All over an append is all over each part, joined by and.
532 law all_append:
533 for ~a: Quant
534 for ~A: Kind(a)
535 for ~f: A -> Bool
536 for xs: List
537 for -ys: List
538 {List.all(~a, ~A, ~f, List.append(a, A, xs, ys)) == Bool.and(List.all(~a, ~A, ~f, xs), List.all(~a, ~A, ~f, ys)) : Bool}
539
540 def all_append(a, A, f, xs, ys):
541 match xs:
542 case Nil{}:
543 {==}
544 case h <> t:
545 %Equal.sym(Bool, List.all(~a, ~A, ~f, List.append(a, A, t, ys)), Bool.and(List.all(~a, ~A, ~f, t), List.all(~a, ~A, ~f, ys)), all_append(~a, ~A, ~f, t, ys)) : {Bool.and(f(h), _) == Bool.and(Bool.and(f(h), List.all(~a, ~A, ~f, t)), List.all(~a, ~A, ~f, ys)) : Bool}
546 Equal.sym(Bool, Bool.and(Bool.and(f(h), List.all(~a, ~A, ~f, t)), List.all(~a, ~A, ~f, ys)), Bool.and(f(h), Bool.and(List.all(~a, ~A, ~f, t), List.all(~a, ~A, ~f, ys))), MBool.and_assoc(f(h), List.all(~a, ~A, ~f, t), List.all(~a, ~A, ~f, ys)))
547
548 # Any over an append is any over each part, joined by or.
549 law any_append:
550 for ~a: Quant
551 for ~A: Kind(a)
552 for ~f: A -> Bool
553 for xs: List
554 for -ys: List
555 {List.any(~a, ~A, ~f, List.append(a, A, xs, ys)) == Bool.or(List.any(~a, ~A, ~f, xs), List.any(~a, ~A, ~f, ys)) : Bool}
556
557 def any_append(a, A, f, xs, ys):
558 match xs:
559 case Nil{}:
560 {==}
561 case h <> t:
562 %Equal.sym(Bool, List.any(~a, ~A, ~f, List.append(a, A, t, ys)), Bool.or(List.any(~a, ~A, ~f, t), List.any(~a, ~A, ~f, ys)), any_append(~a, ~A, ~f, t, ys)) : {Bool.or(f(h), _) == Bool.or(Bool.or(f(h), List.any(~a, ~A, ~f, t)), List.any(~a, ~A, ~f, ys)) : Bool}
563 Equal.sym(Bool, Bool.or(Bool.or(f(h), List.any(~a, ~A, ~f, t)), List.any(~a, ~A, ~f, ys)), Bool.or(f(h), Bool.or(List.any(~a, ~A, ~f, t), List.any(~a, ~A, ~f, ys))), MBool.or_assoc(f(h), List.any(~a, ~A, ~f, t), List.any(~a, ~A, ~f, ys)))
564
565 # Filtering an append filters each part.
566 law filter_append:
567 for ~A: Data
568 for ~f: A -> Bool
569 for xs: List<&2, A>
570 for ys: List<&2, A>
571 {List.filter(~A, ~f, List.append(&2, A, xs, ys)) == List.append(&2, A, List.filter(~A, ~f, xs), List.filter(~A, ~f, ys)) : List<&2, A>}
572
573 def internal_filter_put_append(-A: Data, h: A, r: List<&2, A>, s: List<&2, A>, b: Bool) -> {List.append(&2, A, List.filter.put(A, h, r, b), s) == List.filter.put(A, h, List.append(&2, A, r, s), b) : List<&2, A>}:
574 match b:
575 case False{}:
576 {==}
577 case True{}:
578 {==}
579
580 def filter_append(A, f, xs, ys):
581 match xs:
582 case Nil{}:
583 {==}
584 case +h <> t:
585 +ys = ys
586 +t = t
587 %Equal.sym(List<&2, A>, List.filter(~A, ~f, List.append(&2, A, t, ys)), List.append(&2, A, List.filter(~A, ~f, t), List.filter(~A, ~f, ys)), filter_append(~A, ~f, t, ys)) : {List.filter.put(A, h, _, f(h)) == List.append(&2, A, List.filter.put(A, h, List.filter(~A, ~f, t), f(h)), List.filter(~A, ~f, ys)) : List<&2, A>}
588 Equal.sym(List<&2, A>, List.append(&2, A, List.filter.put(A, h, List.filter(~A, ~f, t), f(h)), List.filter(~A, ~f, ys)), List.filter.put(A, h, List.append(&2, A, List.filter(~A, ~f, t), List.filter(~A, ~f, ys)), f(h)), internal_filter_put_append(A, h, List.filter(~A, ~f, t), List.filter(~A, ~f, ys), f(h)))
589
590 # An append contains x iff either part does.
591 law contains_append:
592 for ~A: Data
593 for ~eq: A -> A -> Bool
594 for xs: List<&2, A>
595 for -ys: List<&2, A>
596 for +x: A
597 {List.contains(~A, ~eq, List.append(&2, A, xs, ys), x) == Bool.or(List.contains(~A, ~eq, xs, x), List.contains(~A, ~eq, ys, x)) : Bool}
598
599 def contains_append(A, eq, xs, ys, x):
600 match xs:
601 case Nil{}:
602 {==}
603 case h <> t:
604 %Equal.sym(Bool, List.contains(~A, ~eq, List.append(&2, A, t, ys), x), Bool.or(List.contains(~A, ~eq, t, x), List.contains(~A, ~eq, ys, x)), contains_append(~A, ~eq, t, ys, x)) : {Bool.or(eq(h, x), _) == Bool.or(Bool.or(eq(h, x), List.contains(~A, ~eq, t, x)), List.contains(~A, ~eq, ys, x)) : Bool}
605 Equal.sym(Bool, Bool.or(Bool.or(eq(h, x), List.contains(~A, ~eq, t, x)), List.contains(~A, ~eq, ys, x)), Bool.or(eq(h, x), Bool.or(List.contains(~A, ~eq, t, x), List.contains(~A, ~eq, ys, x))), MBool.or_assoc(eq(h, x), List.contains(~A, ~eq, t, x), List.contains(~A, ~eq, ys, x)))
606
607 # Filtering never makes a list longer.
608 law length_filter_le:
609 for ~A: Data
610 for ~f: A -> Bool
611 for xs: List<&2, A>
612 {Nat.is_le(List.length(&2, A, List.filter(~A, ~f, xs)), List.length(&2, A, xs)) == True{} : Bool}
613
614 def internal_length_filter_put_le(-A: Data, h: A, r: List<&2, A>, b: Bool) -> {Nat.is_le(List.length(&2, A, List.filter.put(A, h, r, b)), 1n+List.length(&2, A, r)) == True{} : Bool}:
615 match b:
616 case False{}:
617 MNat.le_succ(List.length(&2, A, r))
618 case True{}:
619 MNat.le_refl(1n+List.length(&2, A, r))
620
621 def length_filter_le(A, f, xs):
622 match xs:
623 case Nil{}:
624 {==}
625 case +h <> t:
626 +t = t
627 MNat.le_trans(List.length(&2, A, List.filter.put(A, h, List.filter(~A, ~f, t), f(h))), 1n+List.length(&2, A, List.filter(~A, ~f, t)), 1n+List.length(&2, A, t), internal_length_filter_put_le(A, h, List.filter(~A, ~f, t), f(h)), MNat.succ_le_succ(List.length(&2, A, List.filter(~A, ~f, t)), List.length(&2, A, t), length_filter_le(~A, ~f, t)))
628
629 # --- generated: _sym twins (tools/mathlib/twins.ts), do not edit ---
630
631 # The empty list is a right identity for append: xs ++ [] = xs, reversed to rewrite toward the simple side.
632 law append_nil_sym:
633 for -a: Quant
634 for -A: Kind(a)
635 for xs: List
636 {xs == List.append(a, A, xs, Nil{}) : List}
637
638 def append_nil_sym(a, A, xs):
639 Equal.sym(List, List.append(a, A, xs, Nil{}), xs, append_nil(a, A, xs))
640
641 # The empty list is a left identity for append: [] ++ xs = xs, reversed to rewrite toward the simple side.
642 law nil_append_sym:
643 for -a: Quant
644 for -A: Kind(a)
645 for -xs: List
646 {xs == List.append(a, A, Nil{}, xs) : List}
647
648 def nil_append_sym(a, A, xs):
649 Equal.sym(List, List.append(a, A, Nil{}, xs), xs, nil_append(a, A, xs))
650
651 # Append is associative: (xs ++ ys) ++ zs = xs ++ (ys ++ zs), reversed to rewrite toward the simple side.
652 law append_assoc_sym:
653 for -a: Quant
654 for -A: Kind(a)
655 for xs: List
656 for -ys: List
657 for -zs: List
658 {List.append(a, A, xs, List.append(a, A, ys, zs)) == List.append(a, A, List.append(a, A, xs, ys), zs) : List}
659
660 def append_assoc_sym(a, A, xs, ys, zs):
661 Equal.sym(List, 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))
662
663 # The length of an append is the sum of the lengths, reversed to rewrite toward the simple side.
664 law length_append_sym:
665 for -a: Quant
666 for -A: Kind(a)
667 for xs: List
668 for -ys: List
669 {Nat.add(List.length(a, A, xs), List.length(a, A, ys)) == List.length(a, A, List.append(a, A, xs, ys)) : Nat}
670
671 def length_append_sym(a, A, xs, ys):
672 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))
673
674 # The reverse accumulator loop appends the reversed list to the accumulator, reversed to rewrite toward the simple side.
675 law reverse_go_spec_sym:
676 for -a: Quant
677 for -A: Kind(a)
678 for xs: List
679 for -acc: List
680 {List.append(a, A, List.reverse(a, A, xs), acc) == List.reverse.go(a, A, xs, acc) : List}
681
682 def reverse_go_spec_sym(a, A, xs, acc):
683 Equal.sym(List, List.reverse.go(a, A, xs, acc), List.append(a, A, List.reverse(a, A, xs), acc), reverse_go_spec(a, A, xs, acc))
684
685 # Reversing an append reverses and swaps the parts: reverse (xs ++ ys) = reverse ys ++ reverse xs, reversed to rewrite toward the simple side.
686 law reverse_append_sym:
687 for -a: Quant
688 for -A: Kind(a)
689 for xs: List
690 for ys: List
691 {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}
692
693 def reverse_append_sym(a, A, xs, ys):
694 Equal.sym(List, 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))
695
696 # Reversing twice gives the list back, reversed to rewrite toward the simple side.
697 law reverse_reverse_sym:
698 for -a: Quant
699 for -A: Kind(a)
700 for xs: List
701 {xs == List.reverse(a, A, List.reverse(a, A, xs)) : List}
702
703 def reverse_reverse_sym(a, A, xs):
704 Equal.sym(List, List.reverse(a, A, List.reverse(a, A, xs)), xs, reverse_reverse(a, A, xs))
705
706 # Reversing preserves the length, reversed to rewrite toward the simple side.
707 law length_reverse_sym:
708 for -a: Quant
709 for -A: Kind(a)
710 for xs: List
711 {List.length(a, A, xs) == List.length(a, A, List.reverse(a, A, xs)) : Nat}
712
713 def length_reverse_sym(a, A, xs):
714 Equal.sym(Nat, List.length(a, A, List.reverse(a, A, xs)), List.length(a, A, xs), length_reverse(a, A, xs))
715
716 # A right fold over an append folds the first part onto the fold of the second, reversed to rewrite toward the simple side.
717 law foldr_append_sym:
718 for ~a: Quant
719 for ~A: Kind(a)
720 for ~B: Type
721 for ~f: A -> B -> B
722 for xs: List
723 for -ys: List
724 for -z: B
725 {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}
726
727 def foldr_append_sym(a, A, B, f, xs, ys, z):
728 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))
729
730 # Taking n elements and appending the rest after dropping n gives the list back, reversed to rewrite toward the simple side.
731 law take_append_drop_sym:
732 for -a: Quant
733 for -A: Kind(a)
734 for xs: List
735 for n: Nat
736 {xs == List.append(a, A, List.take(a, A, xs, n), List.drop(a, A, xs, n)) : List}
737
738 def take_append_drop_sym(a, A, xs, n):
739 Equal.sym(List, List.append(a, A, List.take(a, A, xs, n), List.drop(a, A, xs, n)), xs, take_append_drop(a, A, xs, n))
740
741 # Mapping preserves the length, reversed to rewrite toward the simple side.
742 law length_map_sym:
743 for ~A: Type
744 for ~B: Type
745 for ~f: A -> B
746 for xs: List
747 {List.length(&1, A, xs) == List.length(&1, B, List.map(~A, ~B, ~f, xs)) : Nat}
748
749 def length_map_sym(A, B, f, xs):
750 Equal.sym(Nat, List.length(&1, B, List.map(~A, ~B, ~f, xs)), List.length(&1, A, xs), length_map(~A, ~B, ~f, xs))
751
752 # Mapping over an append maps each part: map f (xs ++ ys) = map f xs ++ map f ys, reversed to rewrite toward the simple side.
753 law map_append_sym:
754 for ~A: Type
755 for ~B: Type
756 for ~f: A -> B
757 for xs: List
758 for -ys: List
759 {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}
760
761 def map_append_sym(A, B, f, xs, ys):
762 Equal.sym(List, 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))
763
764 # Mapping twice is mapping the composition: map g (map f xs) = map (g . f) xs, reversed to rewrite toward the simple side.
765 law map_map_sym:
766 for ~A: Type
767 for ~B: Type
768 for ~C: Type
769 for ~f: A -> B
770 for ~g: B -> C
771 for xs: List
772 {List.map(~A, ~C, ~(x => g(f(x))), xs) == List.map(~B, ~C, ~g, List.map(~A, ~B, ~f, xs)) : List}
773
774 def map_map_sym(A, B, C, f, g, xs):
775 Equal.sym(List, 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))
776
777 # Taking zero elements gives the empty list, reversed to rewrite toward the simple side.
778 law take_zero_sym:
779 for -a: Quant
780 for -A: Kind(a)
781 for xs: List
782 {Nil{} == List.take(a, A, xs, 0n) : List}
783
784 def take_zero_sym(a, A, xs):
785 Equal.sym(List, List.take(a, A, xs, 0n), Nil{}, take_zero(a, A, xs))
786
787 # Dropping zero elements gives the list back, reversed to rewrite toward the simple side.
788 law drop_zero_sym:
789 for -a: Quant
790 for -A: Kind(a)
791 for xs: List
792 {xs == List.drop(a, A, xs, 0n) : List}
793
794 def drop_zero_sym(a, A, xs):
795 Equal.sym(List, List.drop(a, A, xs, 0n), xs, drop_zero(a, A, xs))
796
797 # Taking from the empty list gives the empty list, reversed to rewrite toward the simple side.
798 law take_nil_sym:
799 for -a: Quant
800 for -A: Kind(a)
801 for -n: Nat
802 {Nil{} == List.take(a, A, Nil{}, n) : List}
803
804 def take_nil_sym(a, A, n):
805 Equal.sym(List, List.take(a, A, Nil{}, n), Nil{}, take_nil(a, A, n))
806
807 # Dropping from the empty list gives the empty list, reversed to rewrite toward the simple side.
808 law drop_nil_sym:
809 for -a: Quant
810 for -A: Kind(a)
811 for -n: Nat
812 {Nil{} == List.drop(a, A, Nil{}, n) : List}
813
814 def drop_nil_sym(a, A, n):
815 Equal.sym(List, List.drop(a, A, Nil{}, n), Nil{}, drop_nil(a, A, n))
816
817 # Taking n elements leaves min(n, length) of them, reversed to rewrite toward the simple side.
818 law length_take_sym:
819 for -a: Quant
820 for -A: Kind(a)
821 for xs: List
822 for n: Nat
823 {Nat.min(n, List.length(a, A, xs)) == List.length(a, A, List.take(a, A, xs, n)) : Nat}
824
825 def length_take_sym(a, A, xs, n):
826 Equal.sym(Nat, List.length(a, A, List.take(a, A, xs, n)), Nat.min(n, List.length(a, A, xs)), length_take(a, A, xs, n))
827
828 # Dropping n elements leaves length - n of them, reversed to rewrite toward the simple side.
829 law length_drop_sym:
830 for -a: Quant
831 for -A: Kind(a)
832 for xs: List
833 for n: Nat
834 {Nat.sub(List.length(a, A, xs), n) == List.length(a, A, List.drop(a, A, xs, n)) : Nat}
835
836 def length_drop_sym(a, A, xs, n):
837 Equal.sym(Nat, List.length(a, A, List.drop(a, A, xs, n)), Nat.sub(List.length(a, A, xs), n), length_drop(a, A, xs, n))
838
839 # Taking as many elements as the list has gives the list back, reversed to rewrite toward the simple side.
840 law take_length_sym:
841 for -A: Data
842 for +xs: List<&2, A>
843 {xs == List.take(&2, A, xs, List.length(&2, A, xs)) : List<&2, A>}
844
845 def take_length_sym(A, xs):
846 Equal.sym(List<&2, A>, List.take(&2, A, xs, List.length(&2, A, xs)), xs, take_length(A, xs))
847
848 # Dropping as many elements as the list has gives the empty list, reversed to rewrite toward the simple side.
849 law drop_length_sym:
850 for -A: Data
851 for +xs: List<&2, A>
852 {Nil{} == List.drop(&2, A, xs, List.length(&2, A, xs)) : List<&2, A>}
853
854 def drop_length_sym(A, xs):
855 Equal.sym(List<&2, A>, List.drop(&2, A, xs, List.length(&2, A, xs)), Nil{}, drop_length(A, xs))
856
857 # Taking m from the first n is taking min(n, m), reversed to rewrite toward the simple side.
858 law take_take_sym:
859 for -a: Quant
860 for -A: Kind(a)
861 for xs: List
862 for n: Nat
863 for m: Nat
864 {List.take(a, A, xs, Nat.min(n, m)) == List.take(a, A, List.take(a, A, xs, n), m) : List}
865
866 def take_take_sym(a, A, xs, n, m):
867 Equal.sym(List, List.take(a, A, List.take(a, A, xs, n), m), List.take(a, A, xs, Nat.min(n, m)), take_take(a, A, xs, n, m))
868
869 # Dropping m after dropping n is dropping n + m, reversed to rewrite toward the simple side.
870 law drop_drop_sym:
871 for -a: Quant
872 for -A: Kind(a)
873 for xs: List
874 for n: Nat
875 for -m: Nat
876 {List.drop(a, A, xs, Nat.add(n, m)) == List.drop(a, A, List.drop(a, A, xs, n), m) : List}
877
878 def drop_drop_sym(a, A, xs, n, m):
879 Equal.sym(List, List.drop(a, A, List.drop(a, A, xs, n), m), List.drop(a, A, xs, Nat.add(n, m)), drop_drop(a, A, xs, n, m))
880
881 # Reversing the empty list gives the empty list, reversed to rewrite toward the simple side.
882 law reverse_nil_sym:
883 for -a: Quant
884 for -A: Kind(a)
885 {Nil{} == List.reverse(a, A, Nil{}) : List}
886
887 def reverse_nil_sym(a, A):
888 Equal.sym(List, List.reverse(a, A, Nil{}), Nil{}, reverse_nil(a, A))
889
890 # Reversing a one-element list gives it back, reversed to rewrite toward the simple side.
891 law reverse_singleton_sym:
892 for -a: Quant
893 for -A: Kind(a)
894 for -x: A
895 {[x] == List.reverse(a, A, [x]) : List}
896
897 def reverse_singleton_sym(a, A, x):
898 Equal.sym(List, List.reverse(a, A, [x]), [x], reverse_singleton(a, A, x))
899
900 # Replicating x n times gives a list of length n, reversed to rewrite toward the simple side.
901 law length_replicate_sym:
902 for -A: Data
903 for n: Nat
904 for -x: A
905 {n == List.length(&2, A, List.replicate(A, n, x)) : Nat}
906
907 def length_replicate_sym(A, n, x):
908 Equal.sym(Nat, List.length(&2, A, List.replicate(A, n, x)), n, length_replicate(A, n, x))
909
910 # Range(n) has length n, reversed to rewrite toward the simple side.
911 law length_range_sym:
912 for n: Nat
913 {n == List.length(&2, Nat, List.range(n)) : Nat}
914
915 def length_range_sym(n):
916 Equal.sym(Nat, List.length(&2, Nat, List.range(n)), n, length_range(n))
917
918 # Zipping two lists gives the length of the shorter one, reversed to rewrite toward the simple side.
919 law length_zip_sym:
920 for -a: Quant
921 for -A: Kind(a)
922 for xs: List
923 for ys: List
924 {Nat.min(List.length(a, A, xs), List.length(a, A, ys)) == List.length(&1, A & A, List.zip(a, A, a, A, xs, ys)) : Nat}
925
926 def length_zip_sym(a, A, xs, ys):
927 Equal.sym(Nat, List.length(&1, A & A, List.zip(a, A, a, A, xs, ys)), Nat.min(List.length(a, A, xs), List.length(a, A, ys)), length_zip(a, A, xs, ys))
928
929 # Appending after a cons: (x :: xs) ++ ys = x :: (xs ++ ys), reversed to rewrite toward the simple side.
930 law append_cons_sym:
931 for -a: Quant
932 for -A: Kind(a)
933 for -x: A
934 for -xs: List
935 for -ys: List
936 {x <> List.append(a, A, xs, ys) == List.append(a, A, x <> xs, ys) : List}
937
938 def append_cons_sym(a, A, x, xs, ys):
939 Equal.sym(List, List.append(a, A, x <> xs, ys), x <> List.append(a, A, xs, ys), append_cons(a, A, x, xs, ys))
940
941 # The empty list has length zero, reversed to rewrite toward the simple side.
942 law length_nil_sym:
943 for -a: Quant
944 for -A: Kind(a)
945 {0n == List.length(a, A, Nil{}) : Nat}
946
947 def length_nil_sym(a, A):
948 Equal.sym(Nat, List.length(a, A, Nil{}), 0n, length_nil(a, A))
949
950 # A cons is one longer than its tail, reversed to rewrite toward the simple side.
951 law length_cons_sym:
952 for -a: Quant
953 for -A: Kind(a)
954 for -x: A
955 for -xs: List
956 {1n+List.length(a, A, xs) == List.length(a, A, x <> xs) : Nat}
957
958 def length_cons_sym(a, A, x, xs):
959 Equal.sym(Nat, List.length(a, A, x <> xs), 1n+List.length(a, A, xs), length_cons(a, A, x, xs))
960
961 # Concatenating an append concatenates each part: concat (xss ++ yss) = concat xss ++ concat yss, reversed to rewrite toward the simple side.
962 law concat_append_sym:
963 for -a: Quant
964 for -A: Kind(a)
965 for xss: List>
966 for -yss: List>
967 {List.append(a, A, List.concat(a, A, xss), List.concat(a, A, yss)) == List.concat(a, A, List.append(a, List, xss, yss)) : List}
968
969 def concat_append_sym(a, A, xss, yss):
970 Equal.sym(List, List.concat(a, A, List.append(a, List, xss, yss)), List.append(a, A, List.concat(a, A, xss), List.concat(a, A, yss)), concat_append(a, A, xss, yss))
971
972 # A left fold over an append folds the second part from the fold of the first, reversed to rewrite toward the simple side.
973 law foldl_append_sym:
974 for ~a: Quant
975 for ~A: Kind(a)
976 for ~B: Type
977 for ~f: B -> A -> B
978 for xs: List
979 for -ys: List
980 for -z: B
981 {List.foldl(~a, ~A, ~B, ~f, ys, List.foldl(~a, ~A, ~B, ~f, xs, z)) == List.foldl(~a, ~A, ~B, ~f, List.append(a, A, xs, ys), z) : B}
982
983 def foldl_append_sym(a, A, B, f, xs, ys, z):
984 Equal.sym(B, List.foldl(~a, ~A, ~B, ~f, List.append(a, A, xs, ys), z), List.foldl(~a, ~A, ~B, ~f, ys, List.foldl(~a, ~A, ~B, ~f, xs, z)), foldl_append(~a, ~A, ~B, ~f, xs, ys, z))
985
986 # Mapping commutes with reversing: map f (reverse xs) = reverse (map f xs), reversed to rewrite toward the simple side.
987 law map_reverse_sym:
988 for ~A: Type
989 for ~B: Type
990 for ~f: A -> B
991 for xs: List
992 {List.reverse(&1, B, List.map(~A, ~B, ~f, xs)) == List.map(~A, ~B, ~f, List.reverse(&1, A, xs)) : List}
993
994 def map_reverse_sym(A, B, f, xs):
995 Equal.sym(List, List.map(~A, ~B, ~f, List.reverse(&1, A, xs)), List.reverse(&1, B, List.map(~A, ~B, ~f, xs)), map_reverse(~A, ~B, ~f, xs))
996
997 # All over an append is all over each part, joined by and, reversed to rewrite toward the simple side.
998 law all_append_sym:
999 for ~a: Quant
1000 for ~A: Kind(a)
1001 for ~f: A -> Bool
1002 for xs: List
1003 for -ys: List
1004 {Bool.and(List.all(~a, ~A, ~f, xs), List.all(~a, ~A, ~f, ys)) == List.all(~a, ~A, ~f, List.append(a, A, xs, ys)) : Bool}
1005
1006 def all_append_sym(a, A, f, xs, ys):
1007 Equal.sym(Bool, List.all(~a, ~A, ~f, List.append(a, A, xs, ys)), Bool.and(List.all(~a, ~A, ~f, xs), List.all(~a, ~A, ~f, ys)), all_append(~a, ~A, ~f, xs, ys))
1008
1009 # Any over an append is any over each part, joined by or, reversed to rewrite toward the simple side.
1010 law any_append_sym:
1011 for ~a: Quant
1012 for ~A: Kind(a)
1013 for ~f: A -> Bool
1014 for xs: List
1015 for -ys: List
1016 {Bool.or(List.any(~a, ~A, ~f, xs), List.any(~a, ~A, ~f, ys)) == List.any(~a, ~A, ~f, List.append(a, A, xs, ys)) : Bool}
1017
1018 def any_append_sym(a, A, f, xs, ys):
1019 Equal.sym(Bool, List.any(~a, ~A, ~f, List.append(a, A, xs, ys)), Bool.or(List.any(~a, ~A, ~f, xs), List.any(~a, ~A, ~f, ys)), any_append(~a, ~A, ~f, xs, ys))
1020
1021 # Filtering an append filters each part, reversed to rewrite toward the simple side.
1022 law filter_append_sym:
1023 for ~A: Data
1024 for ~f: A -> Bool
1025 for xs: List<&2, A>
1026 for ys: List<&2, A>
1027 {List.append(&2, A, List.filter(~A, ~f, xs), List.filter(~A, ~f, ys)) == List.filter(~A, ~f, List.append(&2, A, xs, ys)) : List<&2, A>}
1028
1029 def filter_append_sym(A, f, xs, ys):
1030 Equal.sym(List<&2, A>, List.filter(~A, ~f, List.append(&2, A, xs, ys)), List.append(&2, A, List.filter(~A, ~f, xs), List.filter(~A, ~f, ys)), filter_append(~A, ~f, xs, ys))
1031
1032 # An append contains x iff either part does, reversed to rewrite toward the simple side.
1033 law contains_append_sym:
1034 for ~A: Data
1035 for ~eq: A -> A -> Bool
1036 for xs: List<&2, A>
1037 for -ys: List<&2, A>
1038 for +x: A
1039 {Bool.or(List.contains(~A, ~eq, xs, x), List.contains(~A, ~eq, ys, x)) == List.contains(~A, ~eq, List.append(&2, A, xs, ys), x) : Bool}
1040
1041 def contains_append_sym(A, eq, xs, ys, x):
1042 Equal.sym(Bool, List.contains(~A, ~eq, List.append(&2, A, xs, ys), x), Bool.or(List.contains(~A, ~eq, xs, x), List.contains(~A, ~eq, ys, x)), contains_append(~A, ~eq, xs, ys, x))
1043
1044 # Filtering never makes a list longer, reversed to rewrite toward the simple side.
1045 law length_filter_le_sym:
1046 for ~A: Data
1047 for ~f: A -> Bool
1048 for xs: List<&2, A>
1049 {True{} == Nat.is_le(List.length(&2, A, List.filter(~A, ~f, xs)), List.length(&2, A, xs)) : Bool}
1050
1051 def length_filter_le_sym(A, f, xs):
1052 Equal.sym(Bool, Nat.is_le(List.length(&2, A, List.filter(~A, ~f, xs)), List.length(&2, A, xs)), True{}, length_filter_le(~A, ~f, xs))