list.bend

bend-mathlib@0.2.0.0 · 1,052 lines · 0 definitions

1# bend-mathlib/list.bend: List lemmas (append, reverse, length, take, drop, map, fold, filter).
2import Base
3import bend-mathlib@0.2.0.0/nat.bend as MNat
4import bend-mathlib@0.2.0.0/bool.bend as MBool
5
6# The empty list is a right identity for append: xs ++ [] = xs.
7law append_nil:
8  for -a: Quant
9  for -A: Kind(a)
10  for xs: List<a, A>
11  {List.append(a, A, xs, Nil{}) == xs : List<a, A>}
12
13def 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<a, A>}
19      {==}
20
21# The empty list is a left identity for append: [] ++ xs = xs.
22law nil_append:
23  for -a: Quant
24  for -A: Kind(a)
25  for -xs: List<a, A>
26  {List.append(a, A, Nil{}, xs) == xs : List<a, A>}
27
28def nil_append(a, A, xs):
29  {==}
30
31# Append is associative: (xs ++ ys) ++ zs = xs ++ (ys ++ zs).
32law append_assoc:
33  for -a: Quant
34  for -A: Kind(a)
35  for xs: List<a, A>
36  for -ys: List<a, A>
37  for -zs: List<a, A>
38  {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>}
39
40def 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<a, A>}
46      {==}
47
48# The length of an append is the sum of the lengths.
49law length_append:
50  for -a: Quant
51  for -A: Kind(a)
52  for xs: List<a, A>
53  for -ys: List<a, A>
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
56def 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
64def 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>}:
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.
72law reverse_go_spec:
73  for -a: Quant
74  for -A: Kind(a)
75  for xs: List<a, A>
76  for -acc: List<a, A>
77  {List.reverse.go(a, A, xs, acc) == List.append(a, A, List.reverse(a, A, xs), acc) : List<a, A>}
78
79def 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
86def 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>}:
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.
94law reverse_append:
95  for -a: Quant
96  for -A: Kind(a)
97  for xs: List<a, A>
98  for ys: List<a, A>
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<a, A>}
100
101def reverse_append(a, A, xs, ys):
102  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)))
103
104def 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>}:
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.
112law reverse_reverse:
113  for -a: Quant
114  for -A: Kind(a)
115  for xs: List<a, A>
116  {List.reverse(a, A, List.reverse(a, A, xs)) == xs : List<a, A>}
117
118def reverse_reverse(a, A, xs):
119  internal_reverse_go_go(a, A, xs, Nil{})
120
121def 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}:
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.
131law length_reverse:
132  for -a: Quant
133  for -A: Kind(a)
134  for xs: List<a, A>
135  {List.length(a, A, List.reverse(a, A, xs)) == List.length(a, A, xs) : Nat}
136
137def 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.
141law 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<a, A>
147  for -ys: List<a, A>
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
151def 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.
160law take_append_drop:
161  for -a: Quant
162  for -A: Kind(a)
163  for xs: List<a, A>
164  for n: Nat
165  {List.append(a, A, List.take(a, A, xs, n), List.drop(a, A, xs, n)) == xs : List<a, A>}
166
167def 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<a, A>}
175      {==}
176
177# Mapping preserves the length.
178law length_map:
179  for ~A: Type
180  for ~B: Type
181  for ~f: A -> B
182  for xs: List<A>
183  {List.length(&1, B, List.map(~A, ~B, ~f, xs)) == List.length(&1, A, xs) : Nat}
184
185def 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.
194law map_append:
195  for ~A: Type
196  for ~B: Type
197  for ~f: A -> B
198  for xs: List<A>
199  for -ys: List<A>
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<B>}
201
202def 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<B>}
208      {==}
209
210# Mapping twice is mapping the composition: map g (map f xs) = map (g . f) xs.
211law 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<A>
218  {List.map(~B, ~C, ~g, List.map(~A, ~B, ~f, xs)) == List.map(~A, ~C, ~(x => g(f(x))), xs) : List<C>}
219
220def 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<C>}
226      {==}
227
228# Taking zero elements gives the empty list.
229law take_zero:
230  for -a: Quant
231  for -A: Kind(a)
232  for xs: List<a, A>
233  {List.take(a, A, xs, 0n) == Nil{} : List<a, A>}
234
235def 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.
243law drop_zero:
244  for -a: Quant
245  for -A: Kind(a)
246  for xs: List<a, A>
247  {List.drop(a, A, xs, 0n) == xs : List<a, A>}
248
249def 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.
257law take_nil:
258  for -a: Quant
259  for -A: Kind(a)
260  for -n: Nat
261  {List.take(a, A, Nil{}, n) == Nil{} : List<a, A>}
262
263def take_nil(a, A, n):
264  {==}
265
266# Dropping from the empty list gives the empty list.
267law drop_nil:
268  for -a: Quant
269  for -A: Kind(a)
270  for -n: Nat
271  {List.drop(a, A, Nil{}, n) == Nil{} : List<a, A>}
272
273def drop_nil(a, A, n):
274  {==}
275
276# Taking n elements leaves min(n, length) of them.
277law length_take:
278  for -a: Quant
279  for -A: Kind(a)
280  for xs: List<a, A>
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
284def 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.
295law length_drop:
296  for -a: Quant
297  for -A: Kind(a)
298  for xs: List<a, A>
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
302def 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.
312law 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
317def 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.
326law 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
331def 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).
339law take_take:
340  for -a: Quant
341  for -A: Kind(a)
342  for xs: List<a, A>
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<a, A>}
346
347def 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<a, A>}
357      {==}
358
359# Dropping m after dropping n is dropping n + m.
360law drop_drop:
361  for -a: Quant
362  for -A: Kind(a)
363  for xs: List<a, A>
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<a, A>}
367
368def 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.
378law reverse_nil:
379  for -a: Quant
380  for -A: Kind(a)
381  {List.reverse(a, A, Nil{}) == Nil{} : List<a, A>}
382
383def reverse_nil(a, A):
384  {==}
385
386# Reversing a one-element list gives it back.
387law reverse_singleton:
388  for -a: Quant
389  for -A: Kind(a)
390  for -x: A
391  {List.reverse(a, A, [x]) == [x] : List<a, A>}
392
393def reverse_singleton(a, A, x):
394  {==}
395
396# Replicating x n times gives a list of length n.
397law 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
403def 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.
412law length_range:
413  for n: Nat
414  {List.length(&2, Nat, List.range(n)) == n : Nat}
415
416def 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
424def 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.
430law length_zip:
431  for -a: Quant
432  for -A: Kind(a)
433  for xs: List<a, A>
434  for ys: List<a, A>
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
437def 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).
448law append_cons:
449  for -a: Quant
450  for -A: Kind(a)
451  for -x: A
452  for -xs: List<a, A>
453  for -ys: List<a, A>
454  {List.append(a, A, x <> xs, ys) == x <> List.append(a, A, xs, ys) : List<a, A>}
455
456def append_cons(a, A, x, xs, ys):
457  {==}
458
459# The empty list has length zero.
460law length_nil:
461  for -a: Quant
462  for -A: Kind(a)
463  {List.length(a, A, Nil{}) == 0n : Nat}
464
465def length_nil(a, A):
466  {==}
467
468# A cons is one longer than its tail.
469law length_cons:
470  for -a: Quant
471  for -A: Kind(a)
472  for -x: A
473  for -xs: List<a, A>
474  {List.length(a, A, x <> xs) == 1n+List.length(a, A, xs) : Nat}
475
476def length_cons(a, A, x, xs):
477  {==}
478
479# Concatenating an append concatenates each part: concat (xss ++ yss) = concat xss ++ concat yss.
480law concat_append:
481  for -a: Quant
482  for -A: Kind(a)
483  for xss: List<a, List<a, A>>
484  for -yss: List<a, List<a, A>>
485  {List.concat(a, A, List.append(a, List<a, A>, xss, yss)) == List.append(a, A, List.concat(a, A, xss), List.concat(a, A, yss)) : List<a, A>}
486
487def concat_append(a, A, xss, yss):
488  match xss:
489    case Nil{}:
490      {==}
491    case h <> t:
492      %Equal.sym(List<a, A>, List.concat(a, A, List.append(a, List<a, A>, 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<a, A>}
493      Equal.sym(List<a, A>, 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.
496law 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<a, A>
502  for -ys: List<a, A>
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
506def 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).
514law map_reverse:
515  for ~A: Type
516  for ~B: Type
517  for ~f: A -> B
518  for xs: List<A>
519  {List.map(~A, ~B, ~f, List.reverse(&1, A, xs)) == List.reverse(&1, B, List.map(~A, ~B, ~f, xs)) : List<B>}
520
521def internal_map_reverse_go(~A: Type, ~B: Type, ~f: A -> B, xs: List<A>, acc: List<A>) -> {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<B>}:
522  match xs:
523    case Nil{}:
524      {==}
525    case h <> t:
526      internal_map_reverse_go(~A, ~B, ~f, t, h <> acc)
527
528def 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.
532law all_append:
533  for ~a: Quant
534  for ~A: Kind(a)
535  for ~f: A -> Bool
536  for xs: List<a, A>
537  for -ys: List<a, A>
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
540def 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.
549law any_append:
550  for ~a: Quant
551  for ~A: Kind(a)
552  for ~f: A -> Bool
553  for xs: List<a, A>
554  for -ys: List<a, A>
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
557def 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.
566law 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
573def 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
580def 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.
591law 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
599def 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.
608law 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
614def 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
621def 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.
632law append_nil_sym:
633  for -a: Quant
634  for -A: Kind(a)
635  for xs: List<a, A>
636  {xs == List.append(a, A, xs, Nil{}) : List<a, A>}
637
638def append_nil_sym(a, A, xs):
639  Equal.sym(List<a, A>, 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.
642law nil_append_sym:
643  for -a: Quant
644  for -A: Kind(a)
645  for -xs: List<a, A>
646  {xs == List.append(a, A, Nil{}, xs) : List<a, A>}
647
648def nil_append_sym(a, A, xs):
649  Equal.sym(List<a, A>, 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.
652law append_assoc_sym:
653  for -a: Quant
654  for -A: Kind(a)
655  for xs: List<a, A>
656  for -ys: List<a, A>
657  for -zs: List<a, A>
658  {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>}
659
660def append_assoc_sym(a, A, xs, ys, zs):
661  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))
662
663# The length of an append is the sum of the lengths, reversed to rewrite toward the simple side.
664law length_append_sym:
665  for -a: Quant
666  for -A: Kind(a)
667  for xs: List<a, A>
668  for -ys: List<a, A>
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
671def 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.
675law reverse_go_spec_sym:
676  for -a: Quant
677  for -A: Kind(a)
678  for xs: List<a, A>
679  for -acc: List<a, A>
680  {List.append(a, A, List.reverse(a, A, xs), acc) == List.reverse.go(a, A, xs, acc) : List<a, A>}
681
682def reverse_go_spec_sym(a, A, xs, acc):
683  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))
684
685# Reversing an append reverses and swaps the parts: reverse (xs ++ ys) = reverse ys ++ reverse xs, reversed to rewrite toward the simple side.
686law reverse_append_sym:
687  for -a: Quant
688  for -A: Kind(a)
689  for xs: List<a, A>
690  for ys: List<a, A>
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<a, A>}
692
693def reverse_append_sym(a, A, xs, ys):
694  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))
695
696# Reversing twice gives the list back, reversed to rewrite toward the simple side.
697law reverse_reverse_sym:
698  for -a: Quant
699  for -A: Kind(a)
700  for xs: List<a, A>
701  {xs == List.reverse(a, A, List.reverse(a, A, xs)) : List<a, A>}
702
703def reverse_reverse_sym(a, A, xs):
704  Equal.sym(List<a, A>, 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.
707law length_reverse_sym:
708  for -a: Quant
709  for -A: Kind(a)
710  for xs: List<a, A>
711  {List.length(a, A, xs) == List.length(a, A, List.reverse(a, A, xs)) : Nat}
712
713def 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.
717law 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<a, A>
723  for -ys: List<a, A>
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
727def 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.
731law take_append_drop_sym:
732  for -a: Quant
733  for -A: Kind(a)
734  for xs: List<a, A>
735  for n: Nat
736  {xs == List.append(a, A, List.take(a, A, xs, n), List.drop(a, A, xs, n)) : List<a, A>}
737
738def take_append_drop_sym(a, A, xs, n):
739  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))
740
741# Mapping preserves the length, reversed to rewrite toward the simple side.
742law length_map_sym:
743  for ~A: Type
744  for ~B: Type
745  for ~f: A -> B
746  for xs: List<A>
747  {List.length(&1, A, xs) == List.length(&1, B, List.map(~A, ~B, ~f, xs)) : Nat}
748
749def 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.
753law map_append_sym:
754  for ~A: Type
755  for ~B: Type
756  for ~f: A -> B
757  for xs: List<A>
758  for -ys: List<A>
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<B>}
760
761def map_append_sym(A, B, f, xs, ys):
762  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))
763
764# Mapping twice is mapping the composition: map g (map f xs) = map (g . f) xs, reversed to rewrite toward the simple side.
765law 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<A>
772  {List.map(~A, ~C, ~(x => g(f(x))), xs) == List.map(~B, ~C, ~g, List.map(~A, ~B, ~f, xs)) : List<C>}
773
774def map_map_sym(A, B, C, f, g, xs):
775  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))
776
777# Taking zero elements gives the empty list, reversed to rewrite toward the simple side.
778law take_zero_sym:
779  for -a: Quant
780  for -A: Kind(a)
781  for xs: List<a, A>
782  {Nil{} == List.take(a, A, xs, 0n) : List<a, A>}
783
784def take_zero_sym(a, A, xs):
785  Equal.sym(List<a, A>, 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.
788law drop_zero_sym:
789  for -a: Quant
790  for -A: Kind(a)
791  for xs: List<a, A>
792  {xs == List.drop(a, A, xs, 0n) : List<a, A>}
793
794def drop_zero_sym(a, A, xs):
795  Equal.sym(List<a, A>, 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.
798law 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<a, A>}
803
804def take_nil_sym(a, A, n):
805  Equal.sym(List<a, A>, 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.
808law 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<a, A>}
813
814def drop_nil_sym(a, A, n):
815  Equal.sym(List<a, A>, 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.
818law length_take_sym:
819  for -a: Quant
820  for -A: Kind(a)
821  for xs: List<a, A>
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
825def 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.
829law length_drop_sym:
830  for -a: Quant
831  for -A: Kind(a)
832  for xs: List<a, A>
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
836def 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.
840law 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
845def 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.
849law 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
854def 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.
858law take_take_sym:
859  for -a: Quant
860  for -A: Kind(a)
861  for xs: List<a, A>
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<a, A>}
865
866def take_take_sym(a, A, xs, n, m):
867  Equal.sym(List<a, A>, 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.
870law drop_drop_sym:
871  for -a: Quant
872  for -A: Kind(a)
873  for xs: List<a, A>
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<a, A>}
877
878def drop_drop_sym(a, A, xs, n, m):
879  Equal.sym(List<a, A>, 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.
882law reverse_nil_sym:
883  for -a: Quant
884  for -A: Kind(a)
885  {Nil{} == List.reverse(a, A, Nil{}) : List<a, A>}
886
887def reverse_nil_sym(a, A):
888  Equal.sym(List<a, A>, 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.
891law reverse_singleton_sym:
892  for -a: Quant
893  for -A: Kind(a)
894  for -x: A
895  {[x] == List.reverse(a, A, [x]) : List<a, A>}
896
897def reverse_singleton_sym(a, A, x):
898  Equal.sym(List<a, A>, 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.
901law 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
907def 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.
911law length_range_sym:
912  for n: Nat
913  {n == List.length(&2, Nat, List.range(n)) : Nat}
914
915def 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.
919law length_zip_sym:
920  for -a: Quant
921  for -A: Kind(a)
922  for xs: List<a, A>
923  for ys: List<a, A>
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
926def 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.
930law append_cons_sym:
931  for -a: Quant
932  for -A: Kind(a)
933  for -x: A
934  for -xs: List<a, A>
935  for -ys: List<a, A>
936  {x <> List.append(a, A, xs, ys) == List.append(a, A, x <> xs, ys) : List<a, A>}
937
938def append_cons_sym(a, A, x, xs, ys):
939  Equal.sym(List<a, A>, 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.
942law length_nil_sym:
943  for -a: Quant
944  for -A: Kind(a)
945  {0n == List.length(a, A, Nil{}) : Nat}
946
947def 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.
951law length_cons_sym:
952  for -a: Quant
953  for -A: Kind(a)
954  for -x: A
955  for -xs: List<a, A>
956  {1n+List.length(a, A, xs) == List.length(a, A, x <> xs) : Nat}
957
958def 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.
962law concat_append_sym:
963  for -a: Quant
964  for -A: Kind(a)
965  for xss: List<a, List<a, A>>
966  for -yss: List<a, List<a, A>>
967  {List.append(a, A, List.concat(a, A, xss), List.concat(a, A, yss)) == List.concat(a, A, List.append(a, List<a, A>, xss, yss)) : List<a, A>}
968
969def concat_append_sym(a, A, xss, yss):
970  Equal.sym(List<a, A>, List.concat(a, A, List.append(a, List<a, A>, 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.
973law 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<a, A>
979  for -ys: List<a, A>
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
983def 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.
987law map_reverse_sym:
988  for ~A: Type
989  for ~B: Type
990  for ~f: A -> B
991  for xs: List<A>
992  {List.reverse(&1, B, List.map(~A, ~B, ~f, xs)) == List.map(~A, ~B, ~f, List.reverse(&1, A, xs)) : List<B>}
993
994def map_reverse_sym(A, B, f, xs):
995  Equal.sym(List<B>, 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.
998law all_append_sym:
999  for ~a: Quant
1000  for ~A: Kind(a)
1001  for ~f: A -> Bool
1002  for xs: List<a, A>
1003  for -ys: List<a, A>
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
1006def 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.
1010law any_append_sym:
1011  for ~a: Quant
1012  for ~A: Kind(a)
1013  for ~f: A -> Bool
1014  for xs: List<a, A>
1015  for -ys: List<a, A>
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
1018def 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.
1022law 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
1029def 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.
1033law 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
1041def 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.
1045law 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
1051def 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))