Unacceptable consequences: why doesn't agda make this proof?
I recently made a type for finite sets in Agda with the following implementation:
open import Relation.Nullary
open import Relation.Nullary.Negation
open import Data.Empty
open import Data.Unit
open import Relation.Binary.PropositionalEquality
open import Data.Nat
suc-inj : (n m : ℕ) → (suc n) ≡ (suc m) → n ≡ m
suc-inj n .n refl = refl
record Eq (A : Set) : Set₁ where
constructor mkEqInst
field
_decide≡_ : (a b : A) → Dec (a ≡ b)
open Eq {{...}}
mutual
data FinSet (A : Set) {{_ : Eq A }} : Set where
ε : FinSet A
_&_ : (a : A) → (X : FinSet A) → .{ p : ¬ (a ∈ X)} → FinSet A
_∈_ : {A : Set} → {{p : Eq A}} → (a : A) → FinSet A → Set
a ∈ ε = ⊥
a ∈ (b & B) with (a decide≡ b)
... | yes _ = ⊤
... | no _ = a ∈ B
_∉_ : {A : Set} → {{p : Eq A}} → (a : A) → FinSet A → Set
_∉_ a X = ¬ (a ∈ X)
decide∈ : {A : Set} → {{_ : Eq A}} → (a : A) → (X : FinSet A) → Dec (a ∈ X)
decide∈ a ε = no (λ z → z)
decide∈ a (b & X) with (a decide≡ b)
decide∈ a (b & X) | yes _ = yes tt
... | no _ = decide∈ a X
decide∉ : {A : Set} → {{_ : Eq A}} → (a : A) → (X : FinSet A) → Dec (a ∉ X)
decide∉ a X = ¬? (decide∈ a X)
instance
eqℕ : Eq ℕ
eqℕ = mkEqInst decide
where decide : (a b : ℕ) → Dec (a ≡ b)
decide zero zero = yes refl
decide zero (suc b) = no (λ ())
decide (suc a) zero = no (λ ())
decide (suc a) (suc b) with (decide a b)
... | yes p = yes (cong suc p)
... | no p = no (λ x → p ((suc-inj a b) x))
However, when I test this type with the following:
test : FinSet ℕ
test = _&_ zero ε
Agda cannot deduce an implicit type argument for some reason ¬ ⊥
! However, the car, of course, is proof of this trivial proposals: λ x → x : ¬ ⊥
.
My question is this: since I noticed the implicit proof as irrelevant, why doesn't Agda just start auto
to find the proof ¬ ⊥
during type checking? Presumably, whenever other implicit arguments are filled in, it might make a difference specifically to Agda finda's proof, so it shouldn't just run auto
, but if the proof was flagged as inappropriate, as in my case, why can't Agda find the proof?
Note. I have a better implementation of this where I directly implement ∉
and Agda can find the relevant proof, but I want to generally understand why Agda cannot automatically find these kinds of proofs for implicit arguments, Is there any way in the current Agda implementation. to get these "automatic implications" as I want here? Or is there a theoretical reason why this would be a bad idea?
source to share
There is no underlying reason why irrelevant arguments cannot be resolved by looking for evidence, however the fear is that in many cases it will be slow and / or not find a solution.
The more user-centric thing is to allow the user to indicate that a specific argument should be inferred using a specific tactic, but this is also not implemented. In your case, you would suggest a tactic that tries to solve the target with (\ x -> x).
source to share
If you give a more direct definition ∉
, then the implicit argument gets the type ⊤
instead ¬ ⊥
. Agda can auto-populate type arguments ⊤
using the eta extension, so your code just works:
open import Relation.Nullary
open import Relation.Nullary.Negation
open import Data.Empty
open import Data.Unit
open import Relation.Binary.PropositionalEquality
open import Data.Nat
suc-inj : (n m : ℕ) → (suc n) ≡ (suc m) → n ≡ m
suc-inj n .n refl = refl
record Eq (A : Set) : Set₁ where
constructor mkEqInst
field
_decide≡_ : (a b : A) → Dec (a ≡ b)
open Eq {{...}}
mutual
data FinSet (A : Set) {{_ : Eq A}} : Set where
ε : FinSet A
_&_ : (a : A) → (X : FinSet A) → .{p : (a ∉ X)} → FinSet A
_∉_ : {A : Set} → {{p : Eq A}} → (a : A) → FinSet A → Set
a ∉ ε = ⊤
a ∉ (b & X) with (a decide≡ b)
... | yes _ = ⊥
... | no _ = a ∉ X
decide∉ : {A : Set} → {{_ : Eq A}} → (a : A) → (X : FinSet A) → Dec (a ∉ X)
decide∉ a ε = yes tt
decide∉ a (b & X) with (a decide≡ b)
... | yes _ = no (λ z → z)
... | no _ = decide∉ a X
instance
eqℕ : Eq ℕ
eqℕ = mkEqInst decide
where decide : (a b : ℕ) → Dec (a ≡ b)
decide zero zero = yes refl
decide zero (suc b) = no (λ ())
decide (suc a) zero = no (λ ())
decide (suc a) (suc b) with (decide a b)
... | yes p = yes (cong suc p)
... | no p = no (λ x → p ((suc-inj a b) x))
test : FinSet ℕ
test = _&_ zero ε
source to share