open import Algebra.Structure.OICM
module Free.LeftRegularMonoid.Base
{X : Set} {_≈_ : X → X → Set} {_≠_ : X → X → Set}
(≠-AR : IsPropDecTightApartnessRelation _≈_ _≠_)
where
open import Data.FreshList.InductiveInductive
open import Data.Sum
open import Relation.Binary.PropositionalEquality
open import Relation.Binary
open import Relation.Nullary using (Dec; yes; no)
open import Data.Product
open import Data.Empty
private
≠-irrefl = IsPropDecTightApartnessRelation.irrefl ≠-AR
≠-sym = IsPropDecTightApartnessRelation.sym ≠-AR
≠-cotrans = IsPropDecTightApartnessRelation.cotrans ≠-AR
≠-prop = IsPropDecTightApartnessRelation.prop ≠-AR
≠-dec = IsPropDecTightApartnessRelation.eqOrApart ≠-AR
≠-cons-cong = WithIrr.cons-cong _≠_ ≠-prop
_≟_ : Decidable _≈_
x ≟ y with ≠-dec x y
... | inj₁ x≈y = yes x≈y
... | inj₂ x≠y = no λ x≈y → ≠-irrefl x≈y x≠y
UniqueList : Set
UniqueList = List# _≠_
≠-resp-≈ : ∀ {x y xs} → x ≈ y → _#_ {R = _≠_} x xs → y # xs
≠-resp-≈ x≈y [] = []
≠-resp-≈ {x} {y} {xs} x≈y (z≠x ∷ x#xs) with ≠-cotrans z≠x y
... | inj₁ x≠y = ⊥-elim (≠-irrefl x≈y x≠y)
... | inj₂ y≠z = y≠z ∷ ≠-resp-≈ x≈y x#xs
mutual
_-[_] : UniqueList → X → UniqueList
[] -[ y ] = []
cons x xs x#xs -[ y ] with ≠-dec x y
... | inj₁ x≈y = xs
... | inj₂ x≠y = cons x (xs -[ y ]) (-[]-fresh xs y x x#xs)
-[]-fresh : (xs : UniqueList) → (y : X) → (z : X) → z # xs → z # (xs -[ y ])
-[]-fresh [] y x z#xs = z#xs
-[]-fresh (cons x xs x#xs) y z (z≠x ∷ z#xs) with ≠-dec x y
... | inj₁ x≈y = z#xs
... | inj₂ x≠y = z≠x ∷ -[]-fresh xs y z z#xs
remove-fresh-idempotent : (xs : UniqueList) → (y : X) → y # xs → xs -[ y ] ≡ xs
remove-fresh-idempotent [] y y#xs = refl
remove-fresh-idempotent (cons x xs x#xs) y (y≠x ∷ y#xs) with ≠-dec x y
... | inj₁ x≈y = ⊥-elim (≠-irrefl x≈y (≠-sym y≠x))
... | inj₂ x≠y = ≠-cons-cong refl (remove-fresh-idempotent xs y y#xs)
remove-removes : (xs : UniqueList) → (y : X) → y # (xs -[ y ])
remove-removes [] y = []
remove-removes (cons x xs x#xs) y with ≠-dec x y
... | inj₁ x≈y = ≠-resp-≈ x≈y x#xs
... | inj₂ x≠y = ≠-sym x≠y ∷ remove-removes xs y
union : UniqueList → UniqueList → UniqueList
union [] ys = ys
union (cons x xs x#xs) ys = cons x (union xs ys -[ x ]) (remove-removes (union xs ys) x)
union-fresh : {a : X} {xs ys : UniqueList} → a # xs → a # ys → a # (union xs ys)
union-fresh {xs = []} a#xs a#ys = a#ys
union-fresh {xs = cons x xs x#xs} (a≠x ∷ a#xs) a#ys = a≠x ∷ -[]-fresh (union xs _) x _ (union-fresh a#xs a#ys)
insert : X → UniqueList → UniqueList
insert x xs = union (cons x [] []) xs