import Data.Boundary
import Data.Sigma
import Data.Vect
import Data.Product
import Data.Iso
 
import Data.Container
import Data.Container.Descriptions.List
import Data.Container.Morphism
import Data.Container.Morphism.Closed
 
import Proofs.Extensionality
import Proofs.Congruence
import Proofs.Sigma

Traversals are Closed lenses

The first observation to make is that the implementation of traversals is already formulated in a way that is compatible with closed lenses \defref{def:closed-lens}. As a reminder, here is the definition of traversal.

record Traversal (a, b : Boundary) where
  constructor MkTraversal
  extract : a.π1 -> Σ Nat (\n => Vect n b.π1 * (Vect n b.π2 -> a.π2))

We can find the correspondance by performing the following series of steps, starting from the definition of traversal with type `Traversal (a, a’) (b, b’):

  • by isomorphism between ⊗ and Σ
  • by currying
  • by isomorphism between and

This last line already has the correct shape to be written as a closed lens with type Closed (a, a') (ls : List b, Vect (length ls) b'). Due to the dependency in the second boundary, this must be a morphism in the category of containers.

But we can do even better. By using two more isomorphisms here is what we can do:

  • , what we had before
  • , by isomorphism
  • by definition of the extension and of

The last expression is actually written in the style of a pointful lens, but as we will see in the next section, it can be written as a monad on .

Traversals are isomorphic to the list monad on container morphisms

From the chapter on monads on containers

---------------------------------------------------------------------------------
-- Traversal is isomorphic to the List Monad on Container
---------------------------------------------------------------------------------
 
vectToFn : {0 a : Type} -> {0 m : Nat} -> Vect m a -> Fin m -> a
vectToFn v i = index i v
 
fnToVect : {0 a : Type} -> {m : Nat} -> (Fin m -> a) -> Vect m a
fnToVect f {m = 0} = []
fnToVect f {m = (S k)} = f FZ :: fnToVect (f . FS)
 
vecIso : {0 a : Type} -> {n : Nat} -> Vect n a `Iso` (Fin n -> a)
vecIso = MkIso
  vectToFn
  fnToVect
  toFrom
  fromTo
  where
    fromTo : {0 n : Nat} -> (x : Vect n a) -> fnToVect (vectToFn x) === x
    fromTo [] = Refl
    fromTo (x :: xs) = cong (x ::) (fromTo xs)
 
    0 toFrom : {m : Nat} -> (fn : Fin m -> a) -> vectToFn {m} (fnToVect {m} fn) === fn
    toFrom {m = 0} fn = funExt $ \w => absurd w
    toFrom {m = (S k)} fn = funExt go
      where
        go : (w : Fin (S k)) -> index w (fn FZ :: fnToVect (\y => fn (FS y))) = fn w
        go FZ = Refl
        go (FS x) = app (vectToFn (fnToVect (fn . FS))) (fn . FS) (toFrom (fn . FS)) x
 
%unbound_implicits on
listIsTraversal : (a :- a') =%> ListCont (b :- b') -> Traversal (MkB a a') (MkB b b')
listIsTraversal (MkMorphism fwd bwd) = MkTraversal $ \x => (fwd x).ex1 ## (vecIso.from (fwd x).ex2 && \vx => bwd x (vecIso.to vx))
 
traversalIsList : Traversal (MkB a a') (MkB b b') -> (a :- a') =%> ListCont (b :- b')
traversalIsList (MkTraversal e) = MkMorphism
  (\x => MkEx (e x).π1 (vecIso.to (e x).π2.π1))
  (\x, f => (e x).π2.π2 (vecIso.from f))
 
lemma : {0 a : Type} -> (f : a -> TyList b) -> (x : a) -> MkEx (f x).ex1 (vectToFn {a=b, m = (f x).ex1} (fnToVect {a=b, m = (f x).ex1} ((f x).ex2))) === (f x)
lemma f x with (f x)
  lemma f x | (MkEx n m) = cong (MkEx n) (vecIso.toFrom m)
 
traversalIso : ((a :- a') =%> ListCont (b :- b')) `Iso` (Traversal (MkB a a') (MkB b b'))
traversalIso = MkIso
  listIsTraversal
  traversalIsList
  pp
  qq
  where
    pp : (zv : Traversal (MkB a a') (MkB b b')) -> listIsTraversal (traversalIsList zv) === zv
    pp (MkTraversal ex) = cong MkTraversal $ funExt $ fg
    where
      fg : (z : a) -> ? === ex z
      fg z with (ex z) proof prf
        fg z | (0 ## ([] && p)) = rewrite sym $ proj1 prf in
              cong2Dep (##) Refl $
              cong2 Product.(&&)
                       { a = fnToVect (vectToFn (((ex z) .π2) .π1))
                       , b = replace {p = \nm => Vect nm b} (sym $ proj1 prf) []
                       , c = (\vx => (ex z).π2.π2 (fnToVect (vectToFn vx)))
                       , d = replace {p = \nm => Vect nm b' -> a'} (sym $ proj1 prf) p}
                       (rewrite prf in Refl)
                       (funExt $ \vx => rewrite vecIso.fromTo vx in rewrite prf in Refl)
        fg z | ((S k) ## (xs && p)) = rewrite sym $ proj1 prf in
              cong2Dep' (##) Refl $
              cong2 Product.(&&)
                  { a = fnToVect (vectToFn (((ex z) .π2) .π1))
                  , b = replace {p = \nm => Vect nm b} (sym $ proj1 prf) xs
                  , c = (\vx => (ex z).π2.π2 (fnToVect (vectToFn vx)))
                  , d = replace {p = \nm => Vect nm b' -> a'} (sym $ proj1 prf) p}
                  (rewrite vecIso.fromTo (((ex z) .π2) .π1) in rewrite prf in Refl)
                  (funExt $ \vx => rewrite vecIso.fromTo vx in rewrite prf in Refl)
 
    0 qq : (x : (a :- a') =%> (ListCont (b :- b'))) -> traversalIsList (listIsTraversal x) === x
    qq (MkMorphism f b) = cong2Dep' MkMorphism
        (funExt $ lemma f)
        (funExtDep $ \v => funExt $ \w => cong (b v) (vecIso.toFrom w))