@@ -62,9 +62,26 @@ Show a => Show (SnocList a) where
62
62
show ' acc (xs : < x) = show' (show x :: acc) xs
63
63
64
64
public export
65
+ mapImpl : (a -> b) -> SnocList a -> SnocList b
66
+ mapImpl f Lin = Lin
67
+ mapImpl f (sx : < x) = (mapImpl f sx) :< (f x)
68
+
69
+ -- Utility for implementing `mapTR`
70
+ mapTR' : List b -> (a -> b) -> SnocList a -> SnocList b
71
+ mapTR' xs f (sx : < x) = mapTR' (f x :: xs) f sx
72
+ mapTR' xs f Lin = Lin <>< xs
73
+
74
+ -- Tail recursive version of `map`. This is automatically used
75
+ -- at runtime due to a `transform` rule.
76
+ mapTR : (a -> b) -> SnocList a -> SnocList b
77
+ mapTR = mapTR' []
78
+
79
+ -- mapTRIsMap proves these are equivalent.
80
+ %transform " tailRecMapSnocList" SnocList . mapImpl = SnocList . mapTR
81
+
82
+ public export % inline
65
83
Functor SnocList where
66
- map f Lin = Lin
67
- map f (sx : < x) = (map f sx) :< (f x)
84
+ map = mapImpl
68
85
69
86
public export
70
87
Semigroup (SnocList a) where
@@ -357,3 +374,75 @@ mapMaybeCast f (x::xs) = do
357
374
mapMaybeStepLemma with (f x)
358
375
_ | Nothing = rewrite appendLinLeftNeutral $ [< ] <>< mapMaybe f xs in Refl
359
376
_ | (Just y) = rewrite fishAsSnocAppend [< y] (mapMaybe f xs) in Refl
377
+
378
+ 0 mapTRIsMap : (f : a -> b) -> (sa : SnocList a) -> mapTR f sa === map f sa
379
+ mapTRIsMap f = lemma []
380
+ where lemma : (bs : List b)
381
+ -> (sa : SnocList a)
382
+ -> mapTR' bs f sa === (map f sa <>< bs)
383
+ lemma bs Lin = Refl
384
+ lemma bs (sx : < x) = lemma (f x :: bs) sx
385
+
386
+
387
+ 0 mapMaybeTRIsMapMaybe : (f : a -> Maybe b)
388
+ -> (sa : SnocList a)
389
+ -> mapMaybeTR f sa === mapMaybe f sa
390
+ mapMaybeTRIsMapMaybe f = lemma []
391
+ where lemma : (bs : List b)
392
+ -> (sa : SnocList a)
393
+ -> mapMaybeAppend bs f sa === (mapMaybe f sa <>< bs)
394
+ lemma bs Lin = Refl
395
+ lemma bs (sx : < x) with (f x)
396
+ lemma bs (sx : < x) | Nothing = lemma bs sx
397
+ lemma bs (sx : < x) | Just v = lemma (v :: bs) sx
398
+
399
+ 0 filterTRIsFilter : (f : a -> Bool )
400
+ -> (sa : SnocList a)
401
+ -> filterTR f sa === filter f sa
402
+ filterTRIsFilter f = lemma []
403
+ where lemma : (as : List a)
404
+ -> (sa : SnocList a)
405
+ -> filterAppend as f sa === (filter f sa <>< as)
406
+ lemma as Lin = Refl
407
+ lemma as (sx : < x) with (f x)
408
+ lemma as (sx : < x) | False = lemma as sx
409
+ lemma as (sx : < x) | True = lemma (x :: as) sx
410
+
411
+ -- SnocList `reverse` applied to `reverseOnto` is equivalent to swapping the
412
+ -- arguments of `reverseOnto`.
413
+ reverseReverseOnto : (l, r : SnocList a) ->
414
+ reverse (reverseOnto l r) = reverseOnto r l
415
+ reverseReverseOnto _ Lin = Refl
416
+ reverseReverseOnto l (sx : < x) = reverseReverseOnto (l :< x) sx
417
+
418
+ ||| SnocList `reverse` applied twice yields the identity function.
419
+ export
420
+ reverseInvolutive : (sx : SnocList a) -> reverse (reverse sx) = sx
421
+ reverseInvolutive = reverseReverseOnto Lin
422
+
423
+ -- Appending `x` to `l` and then reversing the result onto `r` is the same as
424
+ -- using (::) with `x` and the result of reversing `l` onto `r`.
425
+ snocReverse : (x : a) -> (l, r : SnocList a) ->
426
+ reverseOnto r l :< x = reverseOnto r (reverseOnto [<x] (reverse l))
427
+ snocReverse _ Lin _ = Refl
428
+ snocReverse x (sy : < y) r
429
+ = rewrite snocReverse x sy (r : < y) in
430
+ rewrite cong (reverseOnto r . reverse ) $ snocReverse x sy [< y] in
431
+ rewrite reverseInvolutive (reverseOnto [< x] (reverse sy) :< y) in
432
+ Refl
433
+
434
+ -- Proof that it is safe to lift a (::) out of the first `tailRecAppend`
435
+ -- argument.
436
+ snocTailRecAppend : (x : a) -> (l, r : SnocList a) ->
437
+ tailRecAppend l (r :< x) = (tailRecAppend l r) :< x
438
+ snocTailRecAppend x l r =
439
+ rewrite snocReverse x (reverse r) l in
440
+ rewrite reverseInvolutive r in
441
+ Refl
442
+
443
+ -- Proof that `(++)` and `tailRecAppend` do the same thing, so the %transform
444
+ -- directive is safe.
445
+ tailRecAppendIsAppend : (sx, sy : SnocList a) -> tailRecAppend sx sy = sx ++ sy
446
+ tailRecAppendIsAppend sx Lin = Refl
447
+ tailRecAppendIsAppend sx (sy : < y) =
448
+ trans (snocTailRecAppend y sx sy) (cong (:< y) $ tailRecAppendIsAppend sx sy)
0 commit comments