{-# OPTIONS --cubical --allow-unsolved-metas --postfix-projections #-} module Data.Row where open import Prelude open import Data.Nat.Properties using (snotz) open import Data.Bool.Properties using (isPropT) infixr 5 _∷_ data Row (A : Type a) : Type a where [] : Row A _∷_ : A → Row A → Row A swap : ∀ x y xs → x ∷ y ∷ xs ≡ y ∷ x ∷ xs record Alg {a p} (A : Type a) (P : Row A → Type p) : Type (a ℓ⊔ p) where constructor algebra field [_]_∷_⟨_⟩ : (x : A) → (xs : Row A) → (P⟨xs⟩ : P xs) → P (x ∷ xs) [_][] : P [] private _∷_⟨_⟩ = [_]_∷_⟨_⟩ Swap-Coh : Type _ Swap-Coh = ∀ x y xs (P⟨xs⟩ : P xs) → PathP (λ i → P (swap x y xs i)) (x ∷ (y ∷ xs) ⟨ y ∷ xs ⟨ P⟨xs⟩ ⟩ ⟩) (y ∷ (x ∷ xs) ⟨ x ∷ xs ⟨ P⟨xs⟩ ⟩ ⟩) open Alg infixr 2 ψ record ψ {a p} (A : Type a) (P : Row A → Type p) : Type (a ℓ⊔ p) where constructor elim field alg : Alg A P field swap-coh : Swap-Coh alg [_] : ∀ xs → P xs [ [] ] = [ alg ][] [ x ∷ xs ] = [ alg ] x ∷ xs ⟨ [ xs ] ⟩ [ swap x y xs i ] = swap-coh x y xs [ xs ] i syntax ψ ty (λ v → e) = ψ[ v ⦂ ty ] e open ψ record ψ-prop {a p} (A : Type a) (P : Row A → Type p) : Type (a ℓ⊔ p) where constructor elim-prop field p-alg : Alg A P is-prop : ∀ xs → isProp (P xs) prop-swap-coh : Swap-Coh p-alg prop-swap-coh x y xs P⟨xs⟩ = toPathP (is-prop _ (transp (λ i → P (swap x y xs i)) i0 _) _) to-elim : ψ A P to-elim = elim p-alg prop-swap-coh ∥_∥⇓ : ∀ xs → P xs ∥_∥⇓ = [ to-elim ] syntax ψ-prop ty (λ v → e) = ψ[ v ⦂ ty ]∥ e ∥ open ψ-prop foldr : (f : A → B → B) (n : B) (p : ∀ x y xs → f x (f y xs) ≡ f y (f x xs)) → Row A → B foldr f n p = [ elim (algebra (λ x _ xs → f x xs) n) (λ x y _ → p x y) ] length : Row A → ℕ length = foldr (const suc) zero λ _ _ _ → refl infixr 5 _∈_ _∉_ _∈_ : A → Row A → Type _ x ∈ xs = ∃ ys × (x ∷ ys ≡ xs) _∉_ : A → Row A → Type _ x ∉ xs = ¬ (x ∈ xs) union-alg : (ys : Row A) → ψ[ xs ⦂ A ] Row A [ union-alg ys .alg ] x ∷ xs ⟨ P⟨xs⟩ ⟩ = x ∷ P⟨xs⟩ [ union-alg ys .alg ][] = ys union-alg ys .swap-coh x y xs pxs = swap x y pxs _∪_ : Row A → Row A → Row A xs ∪ ys = [ union-alg ys ] xs open import Data.List using (List; _∷_; []) import Data.List as List unorder : List A → Row A unorder = List.foldr _∷_ [] infix 4 _↭_ _↭_ : List A → List A → Type _ xs ↭ ys = unorder xs ≡ unorder ys ↭-refl : {xs : List A} → xs ↭ xs ↭-refl = refl ↭-sym : {xs ys : List A} → xs ↭ ys → ys ↭ xs ↭-sym = sym ↭-trans : {xs ys zs : List A} → xs ↭ ys → ys ↭ zs → xs ↭ zs ↭-trans = _;_ ↭-swap : ∀ {x y : A} {xs} → x ∷ y ∷ xs ↭ y ∷ x ∷ xs ↭-swap = swap _ _ _ open import Relation.Nullary.Decidable.Logic module _ (_≟_ : Discrete A) where _⁻ : A → ψ[ xs ⦂ A ] Row A [ (x ⁻) .alg ] y ∷ xs ⟨ P⟨xs⟩ ⟩ = if does (x ≟ y) then xs else y ∷ P⟨xs⟩ [ (x ⁻) .alg ][] = [] (x ⁻) .swap-coh y z xs pxs with x ≟ y | x ≟ z (x ⁻) .swap-coh y z xs pxs | no _ | no _ = swap y z pxs (x ⁻) .swap-coh y z xs pxs | no _ | yes _ = refl (x ⁻) .swap-coh y z xs pxs | yes _ | no _ = refl (x ⁻) .swap-coh y z xs pxs | yes x≡y | yes x≡z = cong (Row._∷ xs) (sym x≡z ; x≡y) rem-cons : ∀ x xs → [ x ⁻ ] (x ∷ xs) ≡ xs rem-cons x xs with x ≟ x ... | yes _ = refl ... | no ¬p = ⊥-elim (¬p refl) rem-swap : ∀ x y xs → x ≢ y → x ∷ [ y ⁻ ] xs ≡ [ y ⁻ ] (x ∷ xs) rem-swap x y xs x≢y with y ≟ x rem-swap x y xs x≢y | yes x≡y = ⊥-elim (x≢y (sym x≡y)) rem-swap x y xs x≢y | no _ = refl ∷-inj : ∀ x xs ys → x ∷ xs ≡ x ∷ ys → xs ≡ ys ∷-inj x xs ys p with x ≟ x | cong [ x ⁻ ] p ∷-inj x xs ys p | yes _ | q = q ∷-inj x xs ys p | no ¬p | q = ⊥-elim (¬p refl) elem-push : ∀ x y (xs : Row A) → x ≢ y → x ∉ xs → x ∉ y ∷ xs elem-push x y xs x≢y x∉xs (ys , x∷ys≡y∷xs) = let q = rem-swap x y ys x≢y ; cong [ y ⁻ ] x∷ys≡y∷xs ; rem-cons y xs in x∉xs ([ y ⁻ ] ys , q) elem-alg : ∀ x → Alg A (λ xs → Dec (x ∈ xs)) [ elem-alg x ] y ∷ xs ⟨ P⟨xs⟩ ⟩ = disj (λ x≡y → (xs , cong (_∷ xs) x≡y)) (λ { (ys , x∷ys≡xs) → y ∷ ys , swap x y ys ; cong (y ∷_) x∷ys≡xs }) (elem-push x y xs) (x ≟ y) P⟨xs⟩ [ elem-alg x ][] = no (snotz ∘ cong length ∘ snd)