Sorry for my English. I used Google Translate.
Is it real to prove for arbitrary type (X : Set)?
double-negation : ∀ X → ¬ (¬ X)
double-negation = ?
Where:
data ⊥ : Set where
data ¬_ (X : Set) : Set where
¬-constructor : (X → ⊥) → ¬ X
For example, it's simple to prove for ℕ:
data ℕ : Set where
zero : ℕ
suc : ℕ → ℕ
double-negation : ℕ → ¬ (¬ ℕ)
double-negation n =
¬-constructor negation-contradiction
where
negation-contradiction : ¬ ℕ → ⊥
negation-contradiction (¬-constructor ν) = ν n
But after replacing ℕ with X, it can't be checked (because type of n is unknown, consequently type of negation-contradiction is unknown. Also it can't be inferred (I get ¬ n → ⊥)).
How can I prove it?
You cannot prove
∀ X → ¬ (¬ X) (1)
Keep in mind that
ℕ → ¬ (¬ ℕ)
is not an instance of (1) but
∀ X → X → ¬ (¬ X)
which can be proved.
∀ X → ¬ (¬ X) reads like "all propositions are not false". But ⊥ (and many others) is false, so we can actually disprove your statement:
open import Function
open import Relation.Nullary
open import Data.Empty
nope : ¬ ((X : Set) -> ¬ (¬ X))
nope c = c ⊥ id
Related
In Agda, it seems it is not possible to show ∀ {A : Set} (f : ⊥ → A) → f ≡ λ ().
However, the seemingly similar term ∀ {A : Set} (f : ⊤ → A) → f ≡ λ _ → f tt can be proven by refl. It can be later used to prove a form of extensionality for ⊤:
ext⊤ : ∀ {A : Set} (f g : ⊤ → A) (H : ∀ x → f x ≡ g x) → f ≡ g
According to this question and answer, the explanation might be in considering different models of type theory. Is it possible to have any intuition on why one is accepted and not the other? Shouldn't f ≡ λ () be some form of eta law?
The ⊤ type has the eta rule which says that any terms with that type are definitionally equal. Hence, f ≡ (λ x → f x) ≡ (λ x → f tt).
⊥ does not have an eta rule in Agda. If f : ⊥ → A, then we only know that f ≡ λ x → f x. λ () is essentially syntactic sugar for ⊥-elim, and f is not definitionally equal to ⊥-elim.
I draw your attention that the first statement is attempting to prove the uniqueness of ⊥ → A. Usually it is true up to isomorphism.
The full correspondence would have been between ∀ {A : Set} (f : ⊤ → A) → f ≡ λ _ → f tt and ∀ {A : Set} (f : ⊥ → A) → f ≡ λ _ → f () - the expression for ⊤ constructs the value tt, so you should be constructing a value for ⊥.
Agda has no means of constructing a value of ⊥, so () is not a valid constructor, it is only a placeholder for what you want.
Although it isn't really pattern-matching, it probably is not harmful to see the use of () as pattern-matching for the empty type - it is allowed to occur only in the pattern-matching positions.
This is intended to show the similarity is superficial, so should amend your intuition about the expressions.
Shouldn't f ≡ λ () be some form of eta law?
It is not clear what you would gain from that. Many things can be proven only up to isomorphism. So, for example, proving the uniqueness of ⊥ → A could correspond to proving the uniqueness of A → ⊤ (not eta-equality of f and λ _ → f tt). Both of these is doable.
I know that there is an AVL tree in the standard library, but that feels too complex for my purposes. A vanilla function meets most my requirements, except for being able to iterate over the keys.
It is not like I strictly do not know how to make some proposition that for every element in a list there is no duplicate - I did so in Coq once, but I am trying to get a handle on how to bake it into the structure directly and am running into difficulties.
open import Relation.Nullary
open import Relation.Binary.PropositionalEquality
data UniqueList {a} (A : Set a) : Set a
data NotIn {a} {A : Set a} : A → UniqueList A → Set a
data UniqueList A where
[] : UniqueList A
_∷_ : ∀ (x : A) (xs : UniqueList A) → NotIn x xs → UniqueList A
data NotIn {a} {A} where
done : ∀ (x : A) → NotIn x []
dive : ∀ (x y : A) (ys : UniqueList A) (prf : NotIn y ys) → NotIn x ys → ¬ x ≡ y → NotIn x ((y ∷ ys) prf)
I thought I might try something like this, but it feels awkward. Any advice for how to deal with this?
Suppose I have a record type for some algebraic structure; e.g. for monoids:
{-# OPTIONS --cubical #-}
module _ where
open import Cubical.Core.Everything
open import Cubical.Foundations.Everything hiding (assoc)
record Monoid {ℓ} (A : Type ℓ) : Type ℓ where
field
set : isSet A
_⋄_ : A → A → A
e : A
eˡ : ∀ x → e ⋄ x ≡ x
eʳ : ∀ x → x ⋄ e ≡ x
assoc : ∀ x y z → (x ⋄ y) ⋄ z ≡ x ⋄ (y ⋄ z)
Then I can manually create a type for monoid homomorphisms:
record Hom {ℓ ℓ′} {A : Type ℓ} {B : Type ℓ′} (M : Monoid A) (N : Monoid B) : Type (ℓ-max ℓ ℓ′) where
open Monoid M renaming (_⋄_ to _⊕_)
open Monoid N renaming (_⋄_ to _⊗_; e to ε)
field
map : A → B
map-unit : map e ≡ ε
map-op : ∀ x y → map (x ⊕ y) ≡ map x ⊗ map y
But is there a way to define Hom without spelling out the homomorphism laws? So as some kind of mapping from the witness M : Monoid A to N : Monoid B, but that doesn't make much sense to me because it'd be a "mapping" where we already know that it should map M to N...
There currently isn't. But that's what the follow up to the recent paper A feature to unbundle data at will is about. In the repo for that work, you'll find the sources for 'package former'; the accompanying documentation uses Monoid as one of its examples, and section 2.17 is all about homomorphism generation.
The aim of this prototype is to figure out what features are needed (and feasible), to guide the development of both the meta-theory and an 'inside Agda' implementation.
I'm looking for a BetaEq type indexed on a : Term, b : Term, that can be inhabited iff a and b are identical, or if they can be turned into identical terms after a series of beta-reductions. For example, suppose id = (lam (var 0)), a = (app id (app id id)) and b = (app (app id id) id); then we should be able to construct a term of type BetaEq a b, because both sides can be reduced to (app id id). I've attempted this:
data BetaEq : (a : Term) -> (b : Term) -> Set where
refl : (a : Term) -> BetaEq a a
redl : (a : Term) -> (b : Term) -> BetaEq (apply-redex a) b -> BetaEq a b
redr : (a : Term) -> (b : Term) -> BetaEq a (apply-redex b) -> BetaEq a b
Where apply-redex performs a single reduction. But that looks a little invented, so I'm not sure if that's the right way to do it. Note that both terms could diverge, so we can't simply consider normal forms. What is the standard way of representing beta-equality?
Assuming well-scoped untyped lambda terms:
open import Data.Fin
open import Data.Nat
data Tm (n : ℕ) : Set where
var : Fin n → Tm n
app : Tm n → Tm n → Tm n
lam : Tm (suc n) → Tm n
And also a definition of single substitution for the outermost variable (but note that it is always preferable to define single substitution in terms of parallel substitution):
sub : ∀ {n} → Tm n → Tm (suc n) → Tm n
Then beta equality is the congruence closure of beta reduction:
data _~_ {n} : Tm n → Tm n → Set where
β : ∀ {t u} → app (lam t) u ~ sub u t
app : ∀ {t t' u u'} → t ~ t' → u ~ u' → app t u ~ app t' u'
lam : ∀ {t t'} → t ~ t' → lam t ~ lam t'
~refl : ∀ {t} → t ~ t
~sym : ∀ {t t'} → t ~ t' → t' ~ t
~trans : ∀ {t t' t''} → t ~ t' → t' ~ t'' → t ~ t''
By congruence closure, we mean the least relation which is:
An equivalence relation, i.e. one which is reflexive, symmetric and transitive.
A congruence with respect to term constructors, i.e. reduction can take place
inside any constructor.
Implied by one-step beta reduction.
Alternatively, you can give a directed notion of reduction, and then define convertibility as reduction to a common term:
open import Data.Product
open import Relation.Binary.Closure.ReflexiveTransitive
-- one-step reduction
data _~>_ {n} : Tm n → Tm n → Set where
β : ∀ {t u} → app (lam t) u ~> sub u t
app₁ : ∀ {t t' u} → t ~> t' → app t u ~> app t' u
app₂ : ∀ {t u u'} → u ~> u' → app t u ~> app t u'
lam : ∀ {t t'} → t ~> t' → lam t ~> lam t'
-- multi-step reduction as reflexive-transitive closure
_~>*_ : ∀ {n} → Tm n → Tm n → Set
_~>*_ = Star _~>_
_~_ : ∀ {n} → Tm n → Tm n → Set
t ~ u = ∃ λ t' → (t ~>* t') × (u ~>* t')
It depends on the situation which version is more convenient. It is the case that the two definitions are equivalent, but AFAIK proving this equivalence is fairly hard, as it requires showing confluence of reduction.
When dealing with equalities on types in Agda, it is often necessary to coerce the inhabitants the types using a hand-made coercion like
coerce : ∀ {ℓ} {A B : Set ℓ} → A ≡ B → A → B
coerce refl x = x
It was discussed here that explicit coercion of terms could sometimes be avoided using rewriting. I was wondering if this technique worked as well when defining types. So I wrote a little example where f,g : A → Set are two (extentionally) equal dependent types and a property p : A → Set where p x state that every element y : f x is equal to every element z : g x, that is y ≡ z. The last equality is ill-typed, as one can expect since y : f x and z : g x do not share the same type a priori, however I was hoping that rewriting could allow it. Something like:
open import Relation.Binary.PropositionalEquality
postulate A : Set
postulate B : Set
postulate f : A → Set
postulate g : A → Set
postulate f≡g : ∀ {x} → (f x) ≡ (g x)
p : {x : A} → Set
p {x} rewrite f≡g {x} = (y : f x ) (z : g x) → y ≡ z
But the error is still there, even though the rewrite advice is accepted. So, is there a way to make Agda accept this definition without using an explicit coercion, like
p {x} = (y : f x ) (z : g x) → (coerce f≡g y) ≡ z
?
Thank you
Here's a variation of your code that does what you want:
open import Relation.Binary.PropositionalEquality
postulate
A : Set
f : A → Set
g : A → Set
f≡g : ∀ x → f x ≡ g x
p : (x : A) → Set
p x = ∀ y z → R y z
where
R : f x → g x → Set
R fx gx rewrite f≡g x = fx ≡ gx
Why does this work when your version doesn't? rewrite affects two things: (a) the types of variables introduced in patterns left of the rewrite; (b) the goal type. If you look at your rewrite, when it takes effect, there is no f x to be found, so it does nothing. My rewrite, on the other hand, changes the type of fx : f x to g x because fx is introduced before the rewrite.
However, I would be surprised if this helped you much. In my experience, heterogeneous equality (i.e. equality between things of different types) remains annoying, regardless of what tricks you throw at it. For example, consider this variation of your idea, where we define a type R by rewriting:
R : ∀ {x} → f x → g x → Set
R {x} fx gx rewrite f≡g x = fx ≡ gx
R is a heterogenous relation which 'looks' reflexive. However, the closest we can come to stating reflexivity is
coerce : {A B : Set} → A ≡ B → A → B
coerce refl x = x
R-refl : ∀ {x} {fx : f x} → R fx (coerce (f≡g x) fx)
R-refl {x} rewrite f≡g x = refl
Without the coerce, fx would have the wrong type, and so we're back to the problem that we have these coercions polluting our types. This is not necessarily a deal breaker, but it complicates things. So, my advice is to avoid heterogeneous relations if possible.