module Data.List.Any.BagAndSetEquality where
open import Algebra
open import Algebra.FunctionProperties
open import Category.Monad
open import Data.List as List
import Data.List.Properties as LP
open import Data.List.Any as Any using (Any); open Any.Any
open import Data.List.Any.Properties
open import Data.Product
open import Data.Sum
open import Function
open import Function.Equality using (_⟨$⟩_)
import Function.Equivalence as FE
open import Function.Inverse as Inv using (_↔_; module Inverse)
open import Function.Related as Related using (↔⇒; ⌊_⌋; ⌊_⌋→; ⇒→)
open import Function.Related.TypeIsomorphisms
open import Relation.Binary
import Relation.Binary.EqReasoning as EqR
open import Relation.Binary.PropositionalEquality as P
using (_≡_; _≗_)
open import Relation.Binary.Sum
open import Relation.Nullary
open Any.Membership-≡
private
module Eq {k a} {A : Set a} = Setoid ([ k ]-Equality A)
module Ord {k a} {A : Set a} = Preorder ([ k ]-Order A)
module ×⊎ {k ℓ} = CommutativeSemiring (×⊎-CommutativeSemiring k ℓ)
open module ListMonad {ℓ} = RawMonad (List.monad {ℓ = ℓ})
module ListMonoid {a} {A : Set a} = Monoid (List.monoid A)
∷-cong : ∀ {a k} {A : Set a} {x₁ x₂ : A} {xs₁ xs₂} →
x₁ ≡ x₂ → xs₁ ∼[ k ] xs₂ → x₁ ∷ xs₁ ∼[ k ] x₂ ∷ xs₂
∷-cong {x₂ = x} {xs₁} {xs₂} P.refl xs₁≈xs₂ {y} =
y ∈ x ∷ xs₁ ↔⟨ sym $ ∷↔ (_≡_ y) ⟩
(y ≡ x ⊎ y ∈ xs₁) ∼⟨ (y ≡ x ∎) ⊎-cong xs₁≈xs₂ ⟩
(y ≡ x ⊎ y ∈ xs₂) ↔⟨ ∷↔ (_≡_ y) ⟩
y ∈ x ∷ xs₂ ∎
where open Related.EquationalReasoning
map-cong : ∀ {ℓ k} {A B : Set ℓ} {f₁ f₂ : A → B} {xs₁ xs₂} →
f₁ ≗ f₂ → xs₁ ∼[ k ] xs₂ →
List.map f₁ xs₁ ∼[ k ] List.map f₂ xs₂
map-cong {ℓ} {f₁ = f₁} {f₂} {xs₁} {xs₂} f₁≗f₂ xs₁≈xs₂ {x} =
x ∈ List.map f₁ xs₁ ↔⟨ sym $ map↔ {a = ℓ} {b = ℓ} {p = ℓ} ⟩
Any (λ y → x ≡ f₁ y) xs₁ ∼⟨ Any-cong (↔⇒ ∘ helper) xs₁≈xs₂ ⟩
Any (λ y → x ≡ f₂ y) xs₂ ↔⟨ map↔ {a = ℓ} {b = ℓ} {p = ℓ} ⟩
x ∈ List.map f₂ xs₂ ∎
where
open Related.EquationalReasoning
helper : ∀ y → x ≡ f₁ y ↔ x ≡ f₂ y
helper y = record
{ to = P.→-to-⟶ (λ x≡f₁y → P.trans x≡f₁y ( f₁≗f₂ y))
; from = P.→-to-⟶ (λ x≡f₂y → P.trans x≡f₂y (P.sym $ f₁≗f₂ y))
; inverse-of = record
{ left-inverse-of = λ _ → P.proof-irrelevance _ _
; right-inverse-of = λ _ → P.proof-irrelevance _ _
}
}
++-cong : ∀ {a k} {A : Set a} {xs₁ xs₂ ys₁ ys₂ : List A} →
xs₁ ∼[ k ] xs₂ → ys₁ ∼[ k ] ys₂ →
xs₁ ++ ys₁ ∼[ k ] xs₂ ++ ys₂
++-cong {a} {xs₁ = xs₁} {xs₂} {ys₁} {ys₂} xs₁≈xs₂ ys₁≈ys₂ {x} =
x ∈ xs₁ ++ ys₁ ↔⟨ sym $ ++↔ {a = a} {p = a} ⟩
(x ∈ xs₁ ⊎ x ∈ ys₁) ∼⟨ xs₁≈xs₂ ⊎-cong ys₁≈ys₂ ⟩
(x ∈ xs₂ ⊎ x ∈ ys₂) ↔⟨ ++↔ {a = a} {p = a} ⟩
x ∈ xs₂ ++ ys₂ ∎
where open Related.EquationalReasoning
concat-cong : ∀ {a k} {A : Set a} {xss₁ xss₂ : List (List A)} →
xss₁ ∼[ k ] xss₂ → concat xss₁ ∼[ k ] concat xss₂
concat-cong {a} {xss₁ = xss₁} {xss₂} xss₁≈xss₂ {x} =
x ∈ concat xss₁ ↔⟨ sym $ concat↔ {a = a} {p = a} ⟩
Any (Any (_≡_ x)) xss₁ ∼⟨ Any-cong (λ _ → _ ∎) xss₁≈xss₂ ⟩
Any (Any (_≡_ x)) xss₂ ↔⟨ concat↔ {a = a} {p = a} ⟩
x ∈ concat xss₂ ∎
where open Related.EquationalReasoning
>>=-cong : ∀ {ℓ k} {A B : Set ℓ} {xs₁ xs₂} {f₁ f₂ : A → List B} →
xs₁ ∼[ k ] xs₂ → (∀ x → f₁ x ∼[ k ] f₂ x) →
(xs₁ >>= f₁) ∼[ k ] (xs₂ >>= f₂)
>>=-cong {ℓ} {xs₁ = xs₁} {xs₂} {f₁} {f₂} xs₁≈xs₂ f₁≈f₂ {x} =
x ∈ (xs₁ >>= f₁) ↔⟨ sym $ >>=↔ {ℓ = ℓ} {p = ℓ} ⟩
Any (λ y → x ∈ f₁ y) xs₁ ∼⟨ Any-cong (λ x → f₁≈f₂ x) xs₁≈xs₂ ⟩
Any (λ y → x ∈ f₂ y) xs₂ ↔⟨ >>=↔ {ℓ = ℓ} {p = ℓ} ⟩
x ∈ (xs₂ >>= f₂) ∎
where open Related.EquationalReasoning
⊛-cong : ∀ {ℓ k} {A B : Set ℓ} {fs₁ fs₂ : List (A → B)} {xs₁ xs₂} →
fs₁ ∼[ k ] fs₂ → xs₁ ∼[ k ] xs₂ → fs₁ ⊛ xs₁ ∼[ k ] fs₂ ⊛ xs₂
⊛-cong fs₁≈fs₂ xs₁≈xs₂ =
>>=-cong fs₁≈fs₂ λ f →
>>=-cong xs₁≈xs₂ λ x →
_ ∎
where open Related.EquationalReasoning
⊗-cong : ∀ {ℓ k} {A B : Set ℓ} {xs₁ xs₂ : List A} {ys₁ ys₂ : List B} →
xs₁ ∼[ k ] xs₂ → ys₁ ∼[ k ] ys₂ →
(xs₁ ⊗ ys₁) ∼[ k ] (xs₂ ⊗ ys₂)
⊗-cong {ℓ} xs₁≈xs₂ ys₁≈ys₂ =
⊛-cong (⊛-cong (Ord.refl {x = [ _,_ {a = ℓ} {b = ℓ} ]})
xs₁≈xs₂)
ys₁≈ys₂
commutativeMonoid : ∀ {a} → Symmetric-kind → Set a →
CommutativeMonoid _ _
commutativeMonoid {a} k A = record
{ Carrier = List A
; _≈_ = λ xs ys → xs ∼[ ⌊ k ⌋ ] ys
; _∙_ = _++_
; ε = []
; isCommutativeMonoid = record
{ isSemigroup = record
{ isEquivalence = Eq.isEquivalence
; assoc = λ xs ys zs →
Eq.reflexive (ListMonoid.assoc xs ys zs)
; ∙-cong = ++-cong
}
; identityˡ = λ xs {x} → x ∈ xs ∎
; comm = λ xs ys {x} →
x ∈ xs ++ ys ↔⟨ ++↔++ {a = a} {p = a} xs ys ⟩
x ∈ ys ++ xs ∎
}
}
where open Related.EquationalReasoning
empty-unique : ∀ {k a} {A : Set a} {xs : List A} →
xs ∼[ ⌊ k ⌋→ ] [] → xs ≡ []
empty-unique {xs = []} _ = P.refl
empty-unique {xs = _ ∷ _} ∷∼[] with ⇒→ ∷∼[] (here P.refl)
... | ()
++-idempotent : ∀ {a} {A : Set a} →
Idempotent (λ (xs ys : List A) → xs ∼[ set ] ys) _++_
++-idempotent {a} xs {x} =
x ∈ xs ++ xs ∼⟨ FE.equivalence ([ id , id ]′ ∘ _⟨$⟩_ (Inverse.from $ ++↔ {a = a} {p = a}))
(_⟨$⟩_ (Inverse.to $ ++↔ {a = a} {p = a}) ∘ inj₁) ⟩
x ∈ xs ∎
where open Related.EquationalReasoning
>>=-left-distributive :
∀ {ℓ} {A B : Set ℓ} (xs : List A) {f g : A → List B} →
(xs >>= λ x → f x ++ g x) ∼[ bag ] (xs >>= f) ++ (xs >>= g)
>>=-left-distributive {ℓ} xs {f} {g} {y} =
y ∈ (xs >>= λ x → f x ++ g x) ↔⟨ sym $ >>=↔ {ℓ = ℓ} {p = ℓ} ⟩
Any (λ x → y ∈ f x ++ g x) xs ↔⟨ sym (Any-cong (λ _ → ++↔ {a = ℓ} {p = ℓ}) (_ ∎)) ⟩
Any (λ x → y ∈ f x ⊎ y ∈ g x) xs ↔⟨ sym $ ⊎↔ {a = ℓ} {p = ℓ} {q = ℓ} ⟩
(Any (λ x → y ∈ f x) xs ⊎ Any (λ x → y ∈ g x) xs) ↔⟨ >>=↔ {ℓ = ℓ} {p = ℓ} ⟨ ×⊎.+-cong {ℓ = ℓ} ⟩ >>=↔ {ℓ = ℓ} {p = ℓ} ⟩
(y ∈ (xs >>= f) ⊎ y ∈ (xs >>= g)) ↔⟨ ++↔ {a = ℓ} {p = ℓ} ⟩
y ∈ (xs >>= f) ++ (xs >>= g) ∎
where open Related.EquationalReasoning
⊛-left-distributive :
∀ {ℓ} {A B : Set ℓ} (fs : List (A → B)) xs₁ xs₂ →
fs ⊛ (xs₁ ++ xs₂) ∼[ bag ] (fs ⊛ xs₁) ++ (fs ⊛ xs₂)
⊛-left-distributive {B = B} fs xs₁ xs₂ = begin
fs ⊛ (xs₁ ++ xs₂) ≡⟨ P.refl ⟩
(fs >>= λ f → xs₁ ++ xs₂ >>= return ∘ f) ≡⟨ (LP.Monad.cong (P.refl {x = fs}) λ f →
LP.Monad.right-distributive xs₁ xs₂ (return ∘ f)) ⟩
(fs >>= λ f → (xs₁ >>= return ∘ f) ++
(xs₂ >>= return ∘ f)) ≈⟨ >>=-left-distributive fs ⟩
(fs >>= λ f → xs₁ >>= return ∘ f) ++
(fs >>= λ f → xs₂ >>= return ∘ f) ≡⟨ P.refl ⟩
(fs ⊛ xs₁) ++ (fs ⊛ xs₂) ∎
where open EqR ([ bag ]-Equality B)
private
¬-drop-cons :
∀ {a} {A : Set a} {x : A} →
¬ (∀ {xs ys} → x ∷ xs ∼[ set ] x ∷ ys → xs ∼[ set ] ys)
¬-drop-cons {x = x} drop-cons
with FE.Equivalence.to x∼[] ⟨$⟩ here P.refl
where
x,x≈x : (x ∷ x ∷ []) ∼[ set ] [ x ]
x,x≈x = ++-idempotent [ x ]
x∼[] : [ x ] ∼[ set ] []
x∼[] = drop-cons x,x≈x
... | ()
drop-cons : ∀ {a} {A : Set a} {x : A} {xs ys} →
x ∷ xs ∼[ bag ] x ∷ ys → xs ∼[ bag ] ys
drop-cons {A = A} {x} {xs} {ys} x∷xs≈x∷ys {z} = record
{ to = P.→-to-⟶ $ f x∷xs≈x∷ys
; from = P.→-to-⟶ $ f $ Inv.sym x∷xs≈x∷ys
; inverse-of = record
{ left-inverse-of = f∘f x∷xs≈x∷ys
; right-inverse-of = f∘f $ Inv.sym x∷xs≈x∷ys
}
}
where
open Inverse
open P.≡-Reasoning
f : ∀ {xs ys z} → (z ∈ x ∷ xs) ↔ (z ∈ x ∷ ys) → z ∈ xs → z ∈ ys
f inv z∈xs with to inv ⟨$⟩ there z∈xs | left-inverse-of inv (there z∈xs)
f inv z∈xs | there z∈ys | left⁺ = z∈ys
f inv z∈xs | here z≡x | left⁺ with to inv ⟨$⟩ here z≡x | left-inverse-of inv (here z≡x)
f inv z∈xs | here z≡x | left⁺ | there z∈ys | left⁰ = z∈ys
f inv z∈xs | here P.refl | left⁺ | here P.refl | left⁰ with begin
here P.refl ≡⟨ P.sym left⁰ ⟩
from inv ⟨$⟩ here P.refl ≡⟨ left⁺ ⟩
there z∈xs ∎
... | ()
f∘f : ∀ {xs ys z}
(inv : (z ∈ x ∷ xs) ↔ (z ∈ x ∷ ys)) (p : z ∈ xs) →
f (Inv.sym inv) (f inv p) ≡ p
f∘f inv z∈xs with to inv ⟨$⟩ there z∈xs | left-inverse-of inv (there z∈xs)
f∘f inv z∈xs | there z∈ys | left⁺ with from inv ⟨$⟩ there z∈ys | right-inverse-of inv (there z∈ys)
f∘f inv z∈xs | there z∈ys | P.refl | .(there z∈xs) | _ = P.refl
f∘f inv z∈xs | here z≡x | left⁺ with to inv ⟨$⟩ here z≡x | left-inverse-of inv (here z≡x)
f∘f inv z∈xs | here z≡x | left⁺ | there z∈ys | left⁰ with from inv ⟨$⟩ there z∈ys | right-inverse-of inv (there z∈ys)
f∘f inv z∈xs | here z≡x | left⁺ | there z∈ys | P.refl | .(here z≡x) | _ with from inv ⟨$⟩ here z≡x
| right-inverse-of inv (here z≡x)
f∘f inv z∈xs | here z≡x | P.refl | there z∈ys | P.refl | .(here z≡x) | _ | .(there z∈xs) | _ = P.refl
f∘f inv z∈xs | here P.refl | left⁺ | here P.refl | left⁰ with begin
here P.refl ≡⟨ P.sym left⁰ ⟩
from inv ⟨$⟩ here P.refl ≡⟨ left⁺ ⟩
there z∈xs ∎
... | ()