module Prelude.Distinct where open import Data.List.Fresh as F public using ([] ; cons; fresh; _∷#_; map; map-#) renaming (List# to List##) module A where open import Data.List.Fresh.Relation.Unary.All public open import Data.List.Fresh.Relation.Unary.Any public hiding (map) open A public using ([]; _∷_; here; there) open import Data.Unit using (⊤; tt) open import Data.Nat using (ℕ; zero; suc) open import Data.Fin using (Fin; zero; suc) open import Data.Empty open import Data.Product open import Data.Sum open import Relation.Nullary open import Relation.Binary open import Relation.Binary.PropositionalEquality open import Prelude.Level open import Prelude.DecEq List# : Set → Set List# A = List## A _≢_ Fins# : ℕ → Set Fins# n = List# (Fin n) private variable A : Set x y : A xs ys zs : List# A infix 5 _#_ _#_ : A → List# A → Set _ _#_ x xs = fresh _ _≢_ x xs _##_ : List# A → List# A → Set [] ## ys = ⊤ (x ∷# xs) ## ys = x # ys × (xs ## ys) All : (P : A → Set) → List# A → Set _ All P xs = A.All P xs Map : List# A → Set → Set Map xs V = All (λ _ → V) xs infix 5 _#∈_ _#∉_ _#⊆_ _#∈_ _#∉_ : A → List# A → Set _ x #∈ xs = A.Any (x ≡_) xs x #∉ xs = ¬ x #∈ xs _#⊆_ : (xs y : List# A) → Set _ xs #⊆ ys = ∀ {x} → x #∈ xs → x #∈ ys ≡→⊆ : xs ≡ ys → xs #⊆ ys ≡→⊆ refl x = x []⊆xs : [] #⊆ xs []⊆xs () #⊆-refl : xs #⊆ xs #⊆-refl x = x ⊆-trans : xs #⊆ ys → ys #⊆ zs → xs #⊆ zs ⊆-trans xs⊆ys ys⊆zs x∈ = ys⊆zs (xs⊆ys x∈) ∈→¬fresh : (xs : List# A) → x #∈ xs → x # xs → ⊥ ∈→¬fresh (cons y xs _) (here eq) (x≠y , _) = x≠y eq ∈→¬fresh (cons y xs _) (there x∈) (_ , x#xs) = ∈→¬fresh xs x∈ x#xs #∈-uniq : (x∈ x∈′ : x #∈ xs) → x∈ ≡ x∈′ #∈-uniq (here refl) (here refl) = refl #∈-uniq {xs = cons x xs x#xs} (here refl) (there x∈′) = ⊥-elim (∈→¬fresh _ x∈′ x#xs) #∈-uniq {xs = cons x xs x#xs} (there x∈) (here refl) = ⊥-elim (∈→¬fresh _ x∈ x#xs) #∈-uniq (there x∈) (there x∈′) = cong there (#∈-uniq x∈ x∈′) module Decidable {A : Set} ⦃ _ : DecEq A ⦄ where fresh? : (x : A) (xs : List# A) → x # xs ⊎ x #∈ xs fresh? x [] = inj₁ _ fresh? x (cons y xs y#xs) with x ≟ y ... | yes eq = inj₂ (here eq) ... | no neq with fresh? x xs ... | inj₁ x#xs = inj₁ (neq , x#xs) ... | inj₂ x∈xs = inj₂ (there x∈xs) _#∈?_ : (x : A) (xs : List# A) → Dec (x #∈ xs) _#∈?_ x [] = no λ () _#∈?_ x (cons y ys _) with x ≟ y ... | yes p = yes (here p) ... | no ¬p with x #∈? ys ... | yes q = yes (there q) ... | no ¬q = no λ where (here eq) → ¬p eq (there x∈) → ¬q x∈ _#⊆?_ : (xs ys : List# A) → Dec (xs #⊆ ys) _#⊆?_ [] ys = yes λ () _#⊆?_ (cons x xs _) ys with x #∈? ys ... | no ¬p = no λ ⊆ys → ¬p (⊆ys (here refl)) ... | yes p with xs #⊆? ys ... | no ¬q = no λ ⊆ys → ¬q (λ x∈ → ⊆ys (there x∈)) ... | yes q = yes λ where (here refl) → p (there x∈) → q x∈ infixr 8 _∪_ _∪_ : (xs ys : List# A) → List# A fresh-∪ : x # xs → x # ys → x # (xs ∪ ys) [] ∪ ys = ys cons x xs px ∪ ys with fresh? x ys ... | inj₁ x#ys = cons x (xs ∪ ys) (fresh-∪ px x#ys) ... | inj₂ x∈ys = xs ∪ ys fresh-∪ {x} {[]} {ys} _ pys = pys fresh-∪ {x} {cons y xs y#xs} {ys} (px , x#xs) x#ys with fresh? y ys ... | inj₁ y#ys = px , fresh-∪ x#xs x#ys ... | inj₂ y∈ys = fresh-∪ x#xs x#ys ∈-∪⁻ : ∀ {x : A} xs {ys : List# A} → x #∈ xs ∪ ys → x #∈ xs ⊎ x #∈ ys ∈-∪⁻ [] x∈ = inj₂ x∈ ∈-∪⁻ (cons y xs x#xs) {ys} x∈ with fresh? y ys ... | inj₂ ¬pys with ∈-∪⁻ xs x∈ ... | inj₁ x∈xs = inj₁ (there x∈xs) ... | inj₂ x∈ys = inj₂ x∈ys ∈-∪⁻ (cons y xs x#xs) (here eq) | inj₁ pys = inj₁ (here eq) ∈-∪⁻ (cons y xs x#xs) (there x∈) | inj₁ pys with ∈-∪⁻ xs x∈ ... | inj₁ x∈xs = inj₁ (there x∈xs) ... | inj₂ x∈ys = inj₂ x∈ys ∪⁺ʳ : (xs {ys} : List# A) → ys #⊆ xs ∪ ys ∪⁺ʳ [] x∈ = x∈ ∪⁺ʳ (cons x xs pxs) {ys} x∈ with fresh? x ys ... | inj₁ x#ys = there (∪⁺ʳ xs x∈) ... | inj₂ _ = ∪⁺ʳ xs x∈ ∪⁺ˡ : {xs ys : List# A} → xs #⊆ xs ∪ ys ∪⁺ˡ {y ∷# xs} {ys} x∈ with fresh? y ys ∪⁺ˡ {y ∷# xs} (here refl) | inj₂ y∈ys = ∪⁺ʳ xs y∈ys ∪⁺ˡ (there x∈) | inj₂ _ = ∪⁺ˡ x∈ ∪⁺ˡ (here eq) | inj₁ _ = here eq ∪⁺ˡ (there x∈) | inj₁ _ = there (∪⁺ˡ x∈) ∪-⊆⁺ : xs #⊆ zs → ys #⊆ zs → xs ∪ ys #⊆ zs ∪-⊆⁺ {xs} xs⊆ ys⊆ x∈ with ∈-∪⁻ xs x∈ ... | inj₁ ∈xs = xs⊆ ∈xs ... | inj₂ ∈ys = ys⊆ ∈ys ∪-⊆⁻ˡ : xs ∪ ys #⊆ zs → xs #⊆ zs ∪-⊆⁻ˡ xs∪ys⊆zs x∈xs = xs∪ys⊆zs (∪⁺ˡ x∈xs) ∪-⊆⁻ʳ : ∀ xs → xs ∪ ys #⊆ zs → ys #⊆ zs ∪-⊆⁻ʳ xs xs∪ys⊆zs x∈xs = xs∪ys⊆zs (∪⁺ʳ xs x∈xs) ∪-monotoneʳ : ∀ xs → ys #⊆ zs → xs ∪ ys #⊆ xs ∪ zs ∪-monotoneʳ xs ys⊆zs x∈ with ∈-∪⁻ xs x∈ ... | inj₁ x∈xs = ∪⁺ˡ x∈xs ... | inj₂ x∈ys = ∪⁺ʳ xs (ys⊆zs x∈ys) open Decidable public