{-# OPTIONS --rewriting #-}

module A201706.PreludeList where

open import A201706.Prelude public


-- Lists.

data List {} (X : Set ) : Set  where
     : List X
  _,_ : List X  X  List X

inj,₁ :  {} {X : Set } {L L′ : List X} {x x′} 
          L List., x  L′ , x′  L  L′
inj,₁ refl = refl

inj,₂ :  {} {X : Set } {L L′ : List X} {x x′} 
          L List., x  L′ , x′  x  x′
inj,₂ refl = refl

_≟List⟨_⟩_ :  {} {X : Set } (L : List X) (_≟X_ :  (x x′ : X)  Dec (x  x′)) (L′ : List X)  Dec (L  L′)
       ≟List⟨ _≟X_           = yes refl
       ≟List⟨ _≟X_  (L′ , x′) = no λ ()
(L , x) ≟List⟨ _≟X_           = no λ ()
(L , x) ≟List⟨ _≟X_  (L′ , x′) with L ≟List⟨ _≟X_  L′ | x ≟X x′
(L , x) ≟List⟨ _≟X_  (L′ , x′) | yes refl | yes refl = yes refl
(L , x) ≟List⟨ _≟X_  (L′ , x′) | _        | no x≢x′  = no (x≢x′  inj,₂)
(L , x) ≟List⟨ _≟X_  (L′ , x′) | no L≢L′  | _        = no (L≢L′  inj,₁)

length :  {} {X : Set }  List X  Nat
length        = zero
length (L , x) = suc (length L)

lookup :  {} {X : Set }  (L : List X)  Fin (length L)  X
lookup        ()
lookup (L , x) zero    = x
lookup (L , y) (suc i) = lookup L i

map :  { ℓ′} {X : Set } {Y : Set ℓ′}  (X  Y)  List X  List Y
map f        = 
map f (L , x) = map f L , f x

reduce :  { ℓ′} {X : Set } {Y : Set ℓ′}  (Y  X  Y)  Y  List X  Y
reduce f y        = y
reduce f y (L , x) = f (reduce f y L) x


-- Predicates on lists.

data All { ℓ′} {X : Set } (P : Pred X ℓ′) : Pred (List X) ℓ′ where
     : All P 
  _,_ :  {L x}  All P L  P x  All P (L , x)

mapAll :  { ℓ′ ℓ″} {X : Set } {P : Pred X ℓ′} {Q : Pred X ℓ″} {L} 
           (∀ {x}  P x  Q x)  All P L  All Q L
mapAll f        = 
mapAll f (A , a) = mapAll f A , f a

reduceAll :  { ℓ′ ℓ″} {X : Set } {Y : Set ℓ′} {P : Pred X ℓ″} {L} 
             (∀ {x}  Y  P x  Y)  Y  All P L  Y
reduceAll f y        = y
reduceAll f y (A , a) = f (reduceAll f y A) a


-- Order-preserving embeddings on lists.

infix 3 _⊇_
data _⊇_ {} {X : Set } : List X  List X  Set  where
  done :   
  weak :  {L L′ x}  L′  L  L′ , x  L
  lift :  {L L′ x}  L′  L  L′ , x  L , x

injweak⊇ :  {} {X : Set } {L L′ : List X} {x} {η η′ : L′  L} 
             _⊇_.weak {x = x} η  weak η′  η  η′
injweak⊇ refl = refl

injlift⊇ :  {} {X : Set } {L L′ : List X} {x} {η η′ : L′  L} 
             _⊇_.lift {x = x} η  lift η′  η  η′
injlift⊇ refl = refl

_≟⊇_ :  {} {X : Set } {L L′ : List X}  (η η′ : L′  L)  Dec (η  η′)
done   ≟⊇ done    = yes refl
weak η ≟⊇ weak η′ with η ≟⊇ η′
weak η ≟⊇ weak η′ | yes refl = yes refl
weak η ≟⊇ weak η′ | no η≢η′  = no (η≢η′  injweak⊇)
weak η ≟⊇ lift η′ = no λ ()
lift η ≟⊇ weak η′ = no λ ()
lift η ≟⊇ lift η′ with η ≟⊇ η′
lift η ≟⊇ lift η′ | yes refl = yes refl
lift η ≟⊇ lift η′ | no η≢η′  = no (η≢η′  injlift⊇)

unweak⊇ :  {} {X : Set } {L L′ : List X} {x}  L′  L , x  L′  L
unweak⊇ (weak η) = weak (unweak⊇ η)
unweak⊇ (lift η) = weak η

unlift⊇ :  {} {X : Set } {L L′ : List X} {x}  L′ , x  L , x  L′  L
unlift⊇ (weak η) = unweak⊇ η
unlift⊇ (lift η) = η

inf⊇ :  {} {X : Set } {L : List X}  L  
inf⊇ {L = }     = done
inf⊇ {L = L , x} = weak inf⊇

refl⊇ :  {} {X : Set } {L : List X}  L  L
refl⊇ {L = }     = done
refl⊇ {L = L , x} = lift refl⊇

trans⊇ :  {} {X : Set } {L L′ L″ : List X}  L″  L′  L′  L  L″  L
trans⊇ done      η        = η
trans⊇ (weak η′) η        = weak (trans⊇ η′ η)
trans⊇ (lift η′) (weak η) = weak (trans⊇ η′ η)
trans⊇ (lift η′) (lift η) = lift (trans⊇ η′ η)

idtrans⊇₁ :  {} {X : Set } {L L′ : List X} 
              (η : L′  L)  trans⊇ refl⊇ η  η
idtrans⊇₁ done     = refl
idtrans⊇₁ (weak η) = cong weak (idtrans⊇₁ η)
idtrans⊇₁ (lift η) = cong lift (idtrans⊇₁ η)
{-# REWRITE idtrans⊇₁ #-}

idtrans⊇₂ :  {} {X : Set } {L L′ : List X} 
              (η : L′  L)  trans⊇ η refl⊇  η
idtrans⊇₂ done     = refl
idtrans⊇₂ (weak η) = cong weak (idtrans⊇₂ η)
idtrans⊇₂ (lift η) = cong lift (idtrans⊇₂ η)

assoctrans⊇ :  {} {X : Set } {L L′ L″ L‴ : List X} 
                (η″ : L‴  L″) (η′ : L″  L′) (η : L′  L) 
                trans⊇ η″ (trans⊇ η′ η)  trans⊇ (trans⊇ η″ η′) η
assoctrans⊇ done      η′        η        = refl
assoctrans⊇ (weak η″) η′        η        = cong weak (assoctrans⊇ η″ η′ η)
assoctrans⊇ (lift η″) (weak η′) η        = cong weak (assoctrans⊇ η″ η′ η)
assoctrans⊇ (lift η″) (lift η′) (weak η) = cong weak (assoctrans⊇ η″ η′ η)
assoctrans⊇ (lift η″) (lift η′) (lift η) = cong lift (assoctrans⊇ η″ η′ η)

-- ⊇→≥ : ∀ {ℓ} {X : Set ℓ} {L L′ : List X} → L′ ⊇ L → length L′ ≥ length L
-- ⊇→≥ done     = done
-- ⊇→≥ (weak η) = weak (⊇→≥ η)
-- ⊇→≥ (lift η) = lift (⊇→≥ η)
--
-- inf⊇→≥ : ∀ {ℓ} {X : Set ℓ} (L : List X) → ⊇→≥ (inf⊇ {L = L}) ≡ inf≥
-- inf⊇→≥ ∅       = refl
-- inf⊇→≥ (L , x) = cong weak (inf⊇→≥ L)
--
-- refl⊇→≥ : ∀ {ℓ} {X : Set ℓ} (L : List X) → ⊇→≥ (refl⊇ {L = L}) ≡ refl≥
-- refl⊇→≥ ∅       = refl
-- refl⊇→≥ (L , x) = cong lift (refl⊇→≥ L)
--
-- trans⊇→≥ : ∀ {ℓ} {X : Set ℓ} {L L′ L″ : List X} →
--               (η′ : L″ ⊇ L′) (η : L′ ⊇ L) →
--               trans≥ (⊇→≥ η′) (⊇→≥ η) ≡ ⊇→≥ (trans⊇ η′ η)
-- trans⊇→≥ done      η        = refl
-- trans⊇→≥ (weak η′) η        = cong weak (trans⊇→≥ η′ η)
-- trans⊇→≥ (lift η′) (weak η) = cong weak (trans⊇→≥ η′ η)
-- trans⊇→≥ (lift η′) (lift η) = cong lift (trans⊇→≥ η′ η)


-- List membership.

infix 3 _∋_
data _∋_ {} {X : Set } : List X  X  Set  where
  zero :  {L x}    L , x  x
  suc  :  {L x y}  L  x  L , y  x

injsuc∋ :  {} {X : Set } {L : List X} {x y} {𝒾 𝒾′ : L  x} 
            _∋_.suc {y = y} 𝒾  suc 𝒾′  𝒾  𝒾′
injsuc∋ refl = refl

_≟∋_ :  {} {X : Set } {L : List X} {x}  (𝒾 𝒾′ : L  x)  Dec (𝒾  𝒾′)
zero  ≟∋ zero   = yes refl
zero  ≟∋ suc 𝒾′ = no λ ()
suc 𝒾 ≟∋ zero   = no λ ()
suc 𝒾 ≟∋ suc 𝒾′ with 𝒾 ≟∋ 𝒾′
suc 𝒾 ≟∋ suc 𝒾′ | yes refl = yes refl
suc 𝒾 ≟∋ suc 𝒾′ | no 𝒾≢𝒾′  = no (𝒾≢𝒾′  injsuc∋)

idlookup :  {} {X : Set }  (L : List X) (i : Fin (length L)) 
           L  lookup L i
idlookup        ()
idlookup (L , x) zero    = zero
idlookup (L , x) (suc i) = suc (idlookup L i)

lookupAll :  { ℓ′} {X : Set } {P : Pred X ℓ′} {L x} 
              All P L  L  x  P x
lookupAll (A , a) zero    = a
lookupAll (A , b) (suc 𝒾) = lookupAll A 𝒾

mono∋ :  {} {X : Set } {L L′ : List X} {x} 
          L′  L  L  x  L′  x
mono∋ done     ()
mono∋ (weak η) 𝒾       = suc (mono∋ η 𝒾)
mono∋ (lift η) zero    = zero
mono∋ (lift η) (suc 𝒾) = suc (mono∋ η 𝒾)

injmono∋ :  {} {X : Set } {L L′ : List X} {x} 
             (η : L′  L) (𝒾 𝒾′ : L  x) 
             mono∋ η 𝒾  mono∋ η 𝒾′  𝒾  𝒾′
injmono∋ done     ()      ()       p
injmono∋ (weak η) 𝒾       𝒾′       p = injmono∋ η 𝒾 𝒾′ (injsuc∋ p)
injmono∋ (lift η) zero    zero     p = refl
injmono∋ (lift η) zero    (suc 𝒾′) ()
injmono∋ (lift η) (suc 𝒾) zero     ()
injmono∋ (lift η) (suc 𝒾) (suc 𝒾′) p = cong suc (injmono∋ η 𝒾 𝒾′ (injsuc∋ p))

idmono∋ :  {} {X : Set } {L : List X} {x} 
            (𝒾 : L  x)  mono∋ refl⊇ 𝒾  𝒾
idmono∋ zero    = refl
idmono∋ (suc 𝒾) = cong suc (idmono∋ 𝒾)

assocmono∋ :  {} {X : Set } {L L′ L″ : List X} {x} 
               (η′ : L″  L′) (η : L′  L) (𝒾 : L  x) 
               mono∋ η′ (mono∋ η 𝒾)  mono∋ (trans⊇ η′ η) 𝒾
assocmono∋ done      η        𝒾       = idmono∋ (mono∋ η 𝒾)
assocmono∋ (weak η′) η        𝒾       = cong suc (assocmono∋ η′ η 𝒾)
assocmono∋ (lift η′) (weak η) 𝒾       = cong suc (assocmono∋ η′ η 𝒾)
assocmono∋ (lift η′) (lift η) zero    = refl
assocmono∋ (lift η′) (lift η) (suc 𝒾) = cong suc (assocmono∋ η′ η 𝒾)


-- List concatenation.

_⧺_ :  {} {X : Set }  List X  List X  List X
L         = L
L  (K , x) = (L  K) , x

weak⊇⧺ :  {} {X : Set } {L L′ : List X}  L′  L  (K : List X)  L′  K  L
weak⊇⧺ η        = η
weak⊇⧺ η (K , x) = weak (weak⊇⧺ η K)

lift⊇⧺ :  {} {X : Set } {L L′ : List X}  L′  L  (K : List X)  L′  K  L  K
lift⊇⧺ η        = η
lift⊇⧺ η (K , x) = lift (lift⊇⧺ η K)

id⊇⧺₁ :  {} {X : Set }  (L : List X)    L  L
id⊇⧺₁        = done
id⊇⧺₁ (L , x) = lift (id⊇⧺₁ L)

id⊇⧺₂ :  {} {X : Set }  (L : List X)  L    L
id⊇⧺₂ L = refl⊇

weak⊇⧺₁ :  {} {X : Set } {L : List X}  (K : List X)  L  K  K
weak⊇⧺₁ K = trans⊇ (lift⊇⧺ inf⊇ K) (id⊇⧺₁ K)

weak⊇⧺₂ :  {} {X : Set } {L : List X}  (K : List X)  L  K  L
weak⊇⧺₂ K = weak⊇⧺ refl⊇ K

idlift⊇⧺ :  {} {X : Set } {L : List X}  (K : List X)  lift⊇⧺ {L = L} refl⊇ K  refl⊇
idlift⊇⧺        = refl
idlift⊇⧺ (K , x) = cong lift (idlift⊇⧺ K)
{-# REWRITE idlift⊇⧺ #-}

assoclift⊇⧺ :  {} {X : Set } {L L′ L″ : List X} 
                (η′ : L″  L′) (η : L′  L) (K : List X) 
                trans⊇ (lift⊇⧺ η′ K) (lift⊇⧺ η K)  lift⊇⧺ (trans⊇ η′ η) K
assoclift⊇⧺ η′ η        = refl
assoclift⊇⧺ η′ η (K , x) = cong lift (assoclift⊇⧺ η′ η K)
{-# REWRITE assoclift⊇⧺ #-}

invert :  {} {X : Set } {L K : List X}  L  K  Σ (List X)  K′  L  K′)
invert {L = }     {}      done     =  , done
invert {L = L , x} {K}      (weak η) = mapΣ (_, x) lift (invert η)
invert {L = L , x} {K , .x} (lift η) = mapΣ id weak (invert η)