Source code on Github
{-# OPTIONS --safe #-}
module Prelude.Lists.Membership where

open import Prelude.Init; open SetAsType
open L.Mem
open import Prelude.General
open import Prelude.InferenceRules
open import Prelude.Null
open import Prelude.Lists.Core
open import Prelude.Lists.Indexed
open import Prelude.Lists.Empty

private variable
  A : Type ; B : Type ℓ′; C : Type ℓ″
  x x′ y : A; xs ys : List A
  P Q : Pred A 

-- ** Any

module _ {A : Type } {P : Pred A ℓ′} {xs : List A} where
  Is-here Is-there : Pred₀ (Any P xs)
  Is-here = λ where
    (here _)   
    (there _)  
  Is-there = λ where
    (here _)   
    (there _)  

Any-++⁻∘Any-++⁺ˡ : (x∈ : Any P xs)
   L.Any.++⁻ xs {ys} (L.Any.++⁺ˡ {xs = xs}{ys} x∈)
   inj₁ x∈
Any-++⁻∘Any-++⁺ˡ (here _) = refl
Any-++⁻∘Any-++⁺ˡ {ys = ys} (there x∈) rewrite Any-++⁻∘Any-++⁺ˡ {ys = ys} x∈ = refl

Any-++⁻∘Any-++⁺ʳ : (y∈ : Any P ys)
   L.Any.++⁻ xs {ys} (L.Any.++⁺ʳ xs {ys} y∈)
   inj₂ y∈
Any-++⁻∘Any-++⁺ʳ {xs = []} _ = refl
Any-++⁻∘Any-++⁺ʳ {xs = _  xs} y∈ rewrite Any-++⁻∘Any-++⁺ʳ {xs = xs} y∈ = refl

Any-++⁻⇒Any-++⁺ :  {xs ys : List A}
   (x∈ : Any P (xs ++ ys))
    --———————————————————
   case L.Any.++⁻ xs {ys} x∈ of λ where
      (inj₁ x∈ˡ)  x∈  L.Any.++⁺ˡ x∈ˡ
      (inj₂ x∈ʳ)  x∈  L.Any.++⁺ʳ xs x∈ʳ
Any-++⁻⇒Any-++⁺ {xs = []}          x∈       = refl
Any-++⁻⇒Any-++⁺ {xs = x  xs} {ys} (here _) = refl
Any-++⁻⇒Any-++⁺ {xs = x  xs} {ys} (there x∈)
  with IHAny-++⁻⇒Any-++⁺ {xs = xs}{ys} x∈
  with L.Any.++⁻ xs x∈
... | inj₁ x∈ˡ = cong there IH
... | inj₂ x∈ʳ = cong there IH

destruct-Any-++ :  {xs ys : List A}
   (x∈ : Any P (xs ++ ys))
    --——————————————————
   ( λ (x∈ˡ : Any P xs)  x∈  L.Any.++⁺ˡ x∈ˡ)
   ( λ (x∈ʳ : Any P ys)  x∈  L.Any.++⁺ʳ xs x∈ʳ)
destruct-Any-++ {xs = xs}{ys} x∈
  with L.Any.++⁻ xs {ys} x∈ | Any-++⁻⇒Any-++⁺ {xs = xs}{ys} x∈
... | inj₁ x∈ˡ | refl = inj₁ $ -, refl
... | inj₂ x∈ʳ | refl = inj₂ $ -, refl

destruct-Any-++² :  {xs ys zs : List A}
   (x∈ : Any P (xs ++ ys ++ zs))
    --————————————————————————————————————
   ( λ (x∈xs : Any P xs)  x∈  (L.Any.++⁺ˡ x∈xs))
   ( λ (x∈ys : Any P ys)  x∈  (L.Any.++⁺ʳ xs $ L.Any.++⁺ˡ x∈ys))
   ( λ (x∈zs : Any P zs)  x∈  (L.Any.++⁺ʳ xs $ L.Any.++⁺ʳ ys x∈zs))
destruct-Any-++² {xs = xs}{ys} x∈
  with destruct-Any-++ {xs = xs} x∈
... | inj₁ (_   , refl) = inj₁ $ -, refl
... | inj₂ (x∈ʳ , refl)
  with destruct-Any-++ {xs = ys} x∈ʳ
... | inj₁ (_ , refl) = inj₂ $ inj₁ $ -, refl
... | inj₂ (_ , refl) = inj₂ $ inj₂ $ -, refl

-- ** _∈_

∈-++⁻∘∈-++⁺ˡ : (x∈ : x  xs)
   ∈-++⁻ xs {ys} (∈-++⁺ˡ {xs = xs}{ys} x∈)
   inj₁ x∈
∈-++⁻∘∈-++⁺ˡ = Any-++⁻∘Any-++⁺ˡ

∈-++⁻∘∈-++⁺ʳ : (y∈ : y  ys)
   ∈-++⁻ xs {ys} (∈-++⁺ʳ xs {ys} y∈)
   inj₂ y∈
∈-++⁻∘∈-++⁺ʳ = Any-++⁻∘Any-++⁺ʳ

∈-++⁻⇒∈-++⁺ˡ :  {xs ys : List A}
   (x∈ : x  xs ++ ys)
    --———————————————————
   case ∈-++⁻ xs {ys} x∈ of λ where
      (inj₁ x∈ˡ)  x∈  ∈-++⁺ˡ x∈ˡ
      (inj₂ x∈ʳ)  x∈  ∈-++⁺ʳ xs x∈ʳ
∈-++⁻⇒∈-++⁺ˡ {xs = xs} x∈ with ∈-++⁻ xs x∈ | Any-++⁻⇒Any-++⁺ {xs = xs} x∈
... | inj₁ _ | p = p
... | inj₂ _ | p = p

destruct-∈-++ :  {xs ys : List A}
   (x∈ : x  xs ++ ys)
    --——————————————————
   ( λ (x∈ˡ : x  xs)  x∈  ∈-++⁺ˡ x∈ˡ)
   ( λ (x∈ʳ : x  ys)  x∈  ∈-++⁺ʳ xs x∈ʳ)
destruct-∈-++ = destruct-Any-++

destruct-∈-++² :  {xs ys zs : List A}
   (x∈ : x  xs ++ ys ++ zs)
    --————————————————————————————————————
   ( λ (x∈xs : x  xs)  x∈  (∈-++⁺ˡ x∈xs))
   ( λ (x∈ys : x  ys)  x∈  (∈-++⁺ʳ xs $ ∈-++⁺ˡ x∈ys))
   ( λ (x∈zs : x  zs)  x∈  (∈-++⁺ʳ xs $ ∈-++⁺ʳ ys x∈zs))
destruct-∈-++² = destruct-Any-++²

-- ** _⊆_

⊆-tail : x  xs  ys  xs  ys
⊆-tail = _∘ there

module _ {P : Pred A } (P? : Decidable¹ P) where
  ⊆-filter : xs  ys  filter P? xs  filter P? ys
  ⊆-filter {xs = xs}{ys} xs⊆ y∈ =
    let x∈ , Px = ∈-filter⁻ P? y∈
    in ∈-filter⁺ P? (xs⊆ x∈) Px

  destruct-∈-filter :  {x xs} (x∈ : x  xs) (Px : P x) 
    ∈-filter⁻ P? (∈-filter⁺ P? x∈ Px) .proj₁  x∈
  destruct-∈-filter {x} (here refl) Px rewrite dec-yes (P? x) Px .proj₂ = refl
  destruct-∈-filter (there {x = y} x∈) Px
    with IHdestruct-∈-filter x∈ Px
    with P? y
  ... | yes p = cong there IH
  ... | no ¬p = cong there IH

-- ** map
∈-map⁻inverseˡ :  (f : A  B) (f⁻¹ : B  A) 
   Inverse≡ˡ {A = B} f⁻¹ f
   y  map f xs
    ───────────────────────
    f⁻¹ y  xs
∈-map⁻inverseˡ {xs = xs} f f⁻¹ inv y∈ =
  let x , x∈ , eq = ∈-map⁻ f y∈
  in subst (_∈ xs) (sym $ trans (cong f⁻¹ eq) (inv _)) x∈

-- ** mapWith∈

∈-mapWith∈⁻ :  {xs : List A} {f :  {x}  x  xs  B} {y : B}
   y  mapWith∈ xs f
    λ x  Σ (x  xs) λ x∈  y  f {x} x∈
∈-mapWith∈⁻ {xs = x  _}  (here refl) = x , here refl , refl
∈-mapWith∈⁻ {xs = x  xs} (there p)   = let x , x∈ , y≡ = ∈-mapWith∈⁻ p in x , there x∈ , y≡

mapWith∈-∀ :  {xs : List A}  {f :  {x : A}  x  xs  B} {P : B  Type}
   (∀ {x} x∈  P (f {x} x∈))
   (∀ {y}  y  mapWith∈ xs f  P y)
mapWith∈-∀ {xs = x  xs} ∀P {y} (here px)  rewrite px = ∀P (L.Any.here refl)
mapWith∈-∀ {xs = x  xs} ∀P {y} (there y∈) = mapWith∈-∀ (∀P  L.Any.there) y∈

map∘mapWith∈ :  {A B C : Type}
    (g : B  C)  (xs : List A) (f :  {x}  x  xs  B)
   map g (mapWith∈ xs f)  mapWith∈ xs (g  f)
map∘mapWith∈ _ [] _ = refl
map∘mapWith∈ _ (_  _) f = cong (_ ∷_) $ map∘mapWith∈ _ _ (f  there)

mapWith∈∘map :  {A B C : Type}
  (f : A  B) (xs : List A) (g :  {x}  x  map f xs  C)
   mapWith∈ (map f xs) g  mapWith∈ xs (g  ∈-map⁺ f)
mapWith∈∘map _ [] _ = refl
mapWith∈∘map _ (_  _) g = cong (_ ∷_) $ mapWith∈∘map _ _ (g  there)

-- ** Unique

unique-∈ : Unique (x  xs)  x  xs
unique-∈ {xs = []} u ()
unique-∈ {xs = x  xs} ((x≢x  _)  _) (here refl) = x≢x refl
unique-∈ {xs = x  xs} ((_  p)  _)   (there x∈)  = L.All.All¬⇒¬Any p x∈

Unique-mapWith∈ :  {A B : Type} {xs : List A} {f :  {x}  x  xs  B}
   (∀ {x x′} {x∈ : x  xs} {x∈′ : x′  xs}  f x∈  f x∈′  L.Any.index x∈  L.Any.index x∈′)
   Unique (mapWith∈ xs f)
Unique-mapWith∈ {xs = []}     {f = f} f≡ = []
Unique-mapWith∈ {xs = x  xs} {f = f} f≡
  = L.All.tabulate (mapWith∈-∀ {P = f (L.Any.here refl) ≢_} λ _ eq  case f≡ eq of λ () )
   Unique-mapWith∈ {xs = xs} (F.suc-injective  f≡)

-- ** Any/All

All∉[] : All (_∉ []) ys
All∉[] {ys = []}     = []
All∉[] {ys = y  ys} =  ())  All∉[] {ys = ys}

Any-front :  {P : Pred₀ A} {xs : List A}  Any P xs  List A
Any-front {xs = xs} x∈ = take (indexℕ x∈) xs

Any-tail :  {P : Pred₀ A} {xs : List A}  Any P xs  List A
Any-tail {xs = xs} x∈ = drop (suc $ indexℕ x∈) xs
-- Any-tail {xs = _ ∷ xs}     (here _)   = xs
-- Any-tail {xs = _ ∷ _ ∷ xs} (there x∈) = ∈-tail x∈

lookup∈ : (p : Any P xs)  L.Any.lookup p  xs
lookup∈ = λ where
  (here _)   here refl
  (there p)  there $′ lookup∈ p

⊆-resp-Any : _⊆_ Respects˘ (Any P)
⊆-resp-Any xs⊆ = λ where
  (here px)  L.Any.map (λ{ refl  px }) (xs⊆ $ here refl)
  (there p)  ⊆-resp-Any (xs⊆  there) p

-- ** drop

∈-drop⁻ :  {n} {A : Type} {x : A} {xs : List A}
   x  drop n xs
   x  xs
∈-drop⁻ {n = 0} x∈ = x∈
∈-drop⁻ {n = suc n} {xs = _  xs} x∈ = there $ ∈-drop⁻ {n = n} x∈

-- ** splitAt

splitAt-∈-++⁺ˡ :
  (x∈ : x  xs)
   splitAtˡ (ys ++ xs) (index⁺ $ ∈-++⁺ʳ ys x∈)
   ys ++ splitAtˡ xs (index⁺ x∈)
splitAt-∈-++⁺ˡ {ys = []}     _  = refl
splitAt-∈-++⁺ˡ {ys = y  ys} x∈ = cong (y ∷_) (splitAt-∈-++⁺ˡ {ys = ys} x∈)

splitAt-∈-++⁺ʳ :
  (x∈ : x  xs)
   splitAtʳ xs (index⁺ x∈)
   splitAtʳ (ys ++ xs) (index⁺ $ ∈-++⁺ʳ ys x∈)
splitAt-∈-++⁺ʳ {ys = []}     _  = refl
splitAt-∈-++⁺ʳ {ys = _  ys} x∈ = splitAt-∈-++⁺ʳ {ys = ys} x∈

-- ** indexℕ

indexℕ-++⁺ˡ : (x∈ : x  xs)  indexℕ (∈-++⁺ˡ {ys = ys} x∈)  indexℕ x∈
indexℕ-++⁺ˡ = λ where
  (here _)  refl
  (there x∈)  cong suc (indexℕ-++⁺ˡ x∈)

-- ** Last∈

LastAny :  {A : Type } {P : Pred A ℓ′} {xs : List A}  Pred (Any P xs) 
LastAny (there p) = LastAny p
LastAny {xs = _  xs} (here _) = Null xs

Last∈ : Pred (x  xs) _
-- Last = Null ∘ Any-tail
Last∈ = LastAny

Last∈-there⁺ :  (x∈ : x  xs)  Last∈ x∈  Last∈ (there {x = x′} x∈)
Last∈-there⁺ _ = id

module _ (f : P ⊆¹ Q) where
  LastAny-map⁺ :
    (p : Any P xs)
     LastAny p
     LastAny (L.Any.map f p)
  LastAny-map⁺ (here _)  = id
  LastAny-map⁺ (there p) = LastAny-map⁺ p

  LastAny-map⁻ :
    (p : Any P xs)
     LastAny (L.Any.map f p)
     LastAny p
  LastAny-map⁻ (here _)  = id
  LastAny-map⁻ (there p) = LastAny-map⁻ p

module _ (f : A  B) (P : Pred B ) where
  LastAny-map⁺⁺ :
    (p : Any (P  f) xs)
     LastAny p
     LastAny (L.Any.map⁺ {P = P} p)
  LastAny-map⁺⁺ (here _)  refl = refl
  LastAny-map⁺⁺ (there p) lp   = LastAny-map⁺⁺ p lp

Last∈-map⁺ :  (f : A  B) (x∈ : x  xs) 
  Last∈ x∈
  ───────────────────
  Last∈ (∈-map⁺ f x∈)
Last∈-map⁺ f (here _)  refl = refl
Last∈-map⁺ f (there p) lp   = Last∈-map⁺ f p lp

∉-++⁻ :
  x  xs ++ ys
  ───────────────────
  (x  xs) × (x  ys)
∉-++⁻ x∉ = (x∉  ∈-++⁺ˡ) , (x∉  ∈-++⁺ʳ _)

∉-++⁻ˡ : x  xs ++ ys  x  xs
∉-++⁻ˡ = proj₁  ∉-++⁻
∉-++⁻ʳ : x  xs ++ ys  x  ys
∉-++⁻ʳ = proj₂  ∉-++⁻

∉-++⁺ :
   x  xs
   x  ys
    ────────────
    x  xs ++ ys
∉-++⁺ x∉ˡ x∉ʳ = ∈-++⁻ _ >≡> Sum.[ x∉ˡ , x∉ʳ ]

∉-∷⁺ : y  x  y  xs  y  x  xs
∉-∷⁺ y≢ y∉ = λ where
  (here refl)  y≢ refl
  (there y∈)   y∉ y∈

∉-∷⁻ : y  x  xs  y  x × y  xs
∉-∷⁻ y∉ =  where refl  y∉ $ here refl) , y∉  there

module _ (P? : Decidable¹ P) where
  ∉-filter⁻ : x  filter P? xs  P x  x  xs
  ∉-filter⁻ x∉ px = x∉  flip (∈-filter⁺ P?) px

  ∉-filter⁺ : x  xs  x  filter P? xs
  ∉-filter⁺ = _∘ (proj₁  ∈-filter⁻ P?)

-- ** aligning & zipping

{-
∈-alignWith⁺ˡ :
∈-alignWith⁺ʳ :
∈-alignWith⁻ :

∈-zipWith⁺ˡ :
∈-zipWith⁺ʳ :
∈-zipWith⁻ :

∈-unalignWith⁺ˡ :
∈-unalignWith⁺ʳ :
∈-unalignWith⁻ :

∈-unzipWith⁺ˡ :
∈-unzipWith⁺ʳ :
∈-unzipWith⁻ :

∈-partitionSumsWith⁺ˡ
∈-partitionSumsWith⁺ʳ
∈-partitionSumsWith⁻

∈-align⁺ˡ : a ∈ as → this a ∈ align as bs
∈-align⁺ʳ : b ∈ bs → that b ∈ align as bs
∈-align⁻

∈-zip⁺ˡ
∈-zip⁺ʳ
∈-zip⁻

∈-unalign⁺ˡ
∈-unalign⁺ʳ
∈-unalign⁻

∈-unzip⁺ˡ
∈-unzip⁺ʳ
∈-unzip⁻
-}

private variable
  a : A; b : B
  abs abs′ : List (A  B)

∈-partitionSums⁺ˡ ∈-lefts⁺ : inj₁ a  abs  a  lefts abs
∈-partitionSums⁺ˡ {abs = inj₁ _  _} (here refl) = here refl
∈-partitionSums⁺ˡ {abs = inj₁ _  _} (there a∈)  = there $ ∈-partitionSums⁺ˡ a∈
∈-partitionSums⁺ˡ {abs = inj₂ _  _} (there a∈)  = ∈-partitionSums⁺ˡ a∈
∈-lefts⁺ = ∈-partitionSums⁺ˡ

∈-partitionSums⁺ʳ ∈-rights⁺ : inj₂ b  abs  b  rights abs
∈-partitionSums⁺ʳ {abs = inj₂ _  _} (here refl) = here refl
∈-partitionSums⁺ʳ {abs = inj₁ _  _} (there b∈)  = ∈-partitionSums⁺ʳ b∈
∈-partitionSums⁺ʳ {abs = inj₂ _  _} (there b∈)  = there $ ∈-partitionSums⁺ʳ b∈
∈-rights⁺ = ∈-partitionSums⁺ʳ

∈-partitionSums⁻ˡ ∈-lefts⁻ : a  lefts abs  inj₁ a  abs
∈-partitionSums⁻ˡ {abs = inj₁ _  _} (here refl) = here refl
∈-partitionSums⁻ˡ {abs = inj₁ _  _} (there a∈)  = there $′ ∈-partitionSums⁻ˡ a∈
∈-partitionSums⁻ˡ {abs = inj₂ _  _} a∈          = there $′ ∈-partitionSums⁻ˡ a∈
∈-lefts⁻ = ∈-partitionSums⁻ˡ

∈-partitionSums⁻ʳ ∈-rights⁻ : b  rights abs  inj₂ b  abs
∈-partitionSums⁻ʳ {abs = inj₁ _  _} b∈          = there $′ ∈-partitionSums⁻ʳ b∈
∈-partitionSums⁻ʳ {abs = inj₂ _  _} (here refl) = here refl
∈-partitionSums⁻ʳ {abs = inj₂ _  _} (there b∈)  = there $′ ∈-partitionSums⁻ʳ b∈
∈-rights⁻ = ∈-partitionSums⁻ʳ

-- ∈-merge⁺ˡ :
-- ∈-merge⁺ʳ :
-- ∈-merge⁻ :