module Data.Dec.Base where
Decidable types🔗
The type Dec
, of
decisions for a type A
, is a renaming of
the coproduct A ⊎ ¬ A
. A value of Dec A
witnesses not that A
is decidable, but that it has been
decided; A witness of decidability, then, is a proof assigning
decisions to values of a certain type.
data Dec {ℓ} (A : Type ℓ) : Type ℓ where
: (a : A) → Dec A
yes : (¬a : ¬ A) → Dec A
no
Dec-elim: ∀ {ℓ ℓ'} {A : Type ℓ} (P : Dec A → Type ℓ')
→ (∀ y → P (yes y))
→ (∀ y → P (no y))
→ ∀ x → P x
(yes x) = f x
Dec-elim P f g (no x) = g x
Dec-elim P f g
Dec-rec: ∀ {ℓ ℓ'} {A : Type ℓ} {X : Type ℓ'}
→ (A → X)
→ (¬ A → X)
→ Dec A → X
= Dec-elim _ Dec-rec
: ∀ {ℓ} {A : Type ℓ} ⦃ d : Dec A ⦄ → .A → A
recover _ = x
recover ⦃ yes x ⦄ = absurd (¬x x)
recover ⦃ no ¬x ⦄ x
: ∀ {ℓ} {A : Type ℓ} ⦃ d : Dec A ⦄ → ¬ ¬ A → A
dec→dne _ = x
dec→dne ⦃ yes x ⦄ = absurd (¬¬x ¬x) dec→dne ⦃ no ¬x ⦄ ¬¬x
A type is discrete if it has decidable equality.
: ∀ {ℓ} → Type ℓ → Type ℓ
Discrete = {x y : A} → Dec (x ≡ y) Discrete A
private variable
: Level
ℓ ℓ' : Type ℓ A B
If we can construct a pair of maps
and
then we can deduce decidability of
from decidability of
that is, Dec
is an Invariant
functor.
instance
: Invariant (eff Dec)
Invariant-Dec .Invariant.invmap f g (yes a) = yes (f a)
Invariant-Dec .Invariant.invmap f g (no ¬a) = no (¬a ∘ g) Invariant-Dec
This lets us show the following useful lemma: if injects into a discrete type, then is also discrete.
Discrete-inj: (f : A → B)
→ (∀ {x y} → f x ≡ f y → x ≡ y)
→ Discrete B → Discrete A
{x} {y} =
Discrete-inj f inj eq? (ap f) (eq? {f x} {f y}) invmap inj
Programming with decisions🔗
Despite the failure of Dec A
to be a proposition for general
A
, in the 1Lab, we like to work with decisions through
instance search. This is facilitated by the following functions, which
perform instance search:
-- Searches for a type given explicitly.
: ∀ {ℓ} (A : Type ℓ) ⦃ d : Dec A ⦄ → Dec A
holds? = d
holds? A ⦃ d ⦄
-- Searches for equality of inhabitants of a discrete type.
_≡?_ : ⦃ d : Discrete A ⦄ (x y : A) → Dec (x ≡ y)
= holds? (x ≡ y)
x ≡? y
infix 3 _≡?_
And the following operators, which combine instance search with case analysis:
_of_ : ∀ {ℓ ℓ'} (A : Type ℓ) ⦃ d : Dec A ⦄ {B : Type ℓ'} → (Dec A → B) → B
caseᵈ= f (holds? A)
caseᵈ A of f
_return_of_ : ∀ {ℓ ℓ'} (A : Type ℓ) ⦃ d : Dec A ⦄ (B : Dec A → Type ℓ') → (∀ x → B x) → B d
caseᵈ= f (holds? A)
caseᵈ A return P of f
{-# INLINE caseᵈ_of_ #-}
{-# INLINE caseᵈ_return_of_ #-}
private variable
: Type ℓ P Q
We then have the following basic instances for combining decisions, expressing that the class of decidable types is closed under sums, products and functions, and contains the unit type and the empty type.
instance
: ⦃ _ : Dec A ⦄ ⦃ _ : Dec B ⦄ → Dec (A ⊎ B)
Dec-⊎ _ ⦄ = yes (inl A)
Dec-⊎ ⦃ yes A ⦄ ⦃ = yes (inr B)
Dec-⊎ ⦃ no ¬A ⦄ ⦃ yes B ⦄ = no [ ¬A , ¬B ]
Dec-⊎ ⦃ no ¬A ⦄ ⦃ no ¬B ⦄
: ⦃ _ : Dec P ⦄ ⦃ _ : Dec Q ⦄ → Dec (P × Q)
Dec-× {Q = _} ⦃ yes p ⦄ ⦃ yes q ⦄ = yes (p , q)
Dec-× {Q = _} ⦃ yes p ⦄ ⦃ no ¬q ⦄ = no λ z → ¬q (snd z)
Dec-× {Q = _} ⦃ no ¬p ⦄ ⦃ _ ⦄ = no λ z → ¬p (fst z)
Dec-×
: ⦃ _ : Dec P ⦄ ⦃ _ : Dec Q ⦄ → Dec (P → Q)
Dec-→ {Q = _} ⦃ yes p ⦄ ⦃ yes q ⦄ = yes λ _ → q
Dec-→ {Q = _} ⦃ yes p ⦄ ⦃ no ¬q ⦄ = no λ pq → ¬q (pq p)
Dec-→ {Q = _} ⦃ no ¬p ⦄ ⦃ q ⦄ = yes λ p → absurd (¬p p)
Dec-→ {-# INCOHERENT Dec-→ #-}
: Dec ⊤
Dec-⊤ = yes tt
Dec-⊤
: Dec ⊥
Dec-⊥ = no id
Dec-⊥
: ∀ {ℓ ℓ'} {A : Type ℓ} → ⦃ Dec A ⦄ → Dec (Lift ℓ' A)
Dec-Lift = Lift-≃ e⁻¹ <≃> d Dec-Lift ⦃ d ⦄
These closure properties make Dec
a Monoidal
and Alternative
functor.
instance
: Monoidal (eff Dec)
Monoidal-Dec .Monoidal.munit = Dec-⊤
Monoidal-Dec .Monoidal._<,>_ a b = Dec-× ⦃ a ⦄ ⦃ b ⦄
Monoidal-Dec
: Alternative (eff Dec)
Alternative-Dec .Alternative.empty = Dec-⊥
Alternative-Dec .Alternative._<+>_ a b = Dec-⊎ ⦃ a ⦄ ⦃ b ⦄ Alternative-Dec
infix 0 ifᵈ_then_else_
_then_else_ : Dec A → B → B → B
ifᵈ= y
ifᵈ yes a then y else n = n
ifᵈ no ¬a then y else n
: ∀ {ℓ} {A : Type ℓ} → Dec A → Type
is-yes (yes x) = ⊤
is-yes (no _) = ⊥
is-yes
: ∀ {ℓ} {A : Type ℓ} ⦃ d : Dec A ⦄ {_ : is-yes d} → A
decide! = x decide! ⦃ yes x ⦄
Relation to sums🔗
The decidability of can also be phrased as so we provide helpers to convert between the two.
: Dec A → A ⊎ ¬ A
from-dec (yes a) = inl a
from-dec (no ¬a) = inr ¬a
from-dec
: A ⊎ ¬ A → Dec A
to-dec (inl a) = yes a
to-dec (inr ¬a) = no ¬a to-dec
The proof that these functions are inverses is automatic by computation, and thus it can be shown they are equivalences:
: {A : Type ℓ} → is-equiv (from-dec {A = A})
from-dec-is-equiv = is-iso→is-equiv (iso to-dec p q) where
from-dec-is-equiv : _
p (inl x) = refl
p (inr ¬x) = refl
p
: _
q (yes x) = refl
q (no x) = refl q
: ∀ {A : Type ℓ} → Dec A → Bool
Dec→Bool (yes x) = true
Dec→Bool (no ¬x) = false Dec→Bool