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))