Parametricity-exploiting proofs in Agda - agda

Reading this answer prompted me to try to construct, and then prove, the canonical form of polymorphic container functions. The construction was straightforward, but the proof stumps me. Below is a simplified-minimized version of how I tried to write the proof.
The simplified version is proving that sufficiently polymorphic functions, due to parametricity, can't change their behaviour only based on the choice of parameter. Let's say we have functions of two arguments, one of a fixed type and one parametric:
PolyFun : Set → Set _
PolyFun A = ∀ {X : Set} → A → X → A
the property I'd like to prove:
open import Relation.Binary.PropositionalEquality
parametricity : ∀ {A X Y} → (f : PolyFun A) → ∀ a x y → f {X} a x ≡ f {Y} a y
parametricity f a x y = {!!}
Are statements like that provable from inside Agda?

Nope, there's no parametricity principle accessible in Agda (yet! [1]).
However you can use these combinators to build the type of the corresponding free theorem and postulate it:
http://wiki.portal.chalmers.se/agda/pmwiki.php?n=Libraries.LightweightFreeTheorems
[1] http://www.cse.chalmers.se/~mouling/share/PresheafModelParametericTT.pdf

Related

Pointwise Equality ≗ vs Propositional Equality ≡ in Agda

When trying to prove a property over functions using list, I had to prove that the property is preserved by map over a list. Gladly, I found this useful congruence proof in Agda's standard library (here):
map-cong : ∀ {f g : A → B} → f ≗ g → map f ≗ map g
map-cong f≗g [] = refl
map-cong f≗g (x ∷ xs) = cong₂ _∷_ (f≗g x) (map-cong f≗g xs)
I am trying to do my proof with respect to propositional equality ≡ but map-cong proves pointwise equality ≗. I have several questions here:
I noticed that map-cong was previously implemented via ≡ but was generalized (I found this issue). This suggests that ≗ is a generalization of ≡. Is there a way to conclude propositional equality from pointwise equality? Something like a function f ≗ g → f ≡ g?
When looking at the implementation, point-wise equality seems to be defined as propositional equality for functions via the extensionality axiom: Two functions are equal if they yield the same results for all inputs. This is emphasized by the above definition of map-cong which indeed matches not only on the proof f≗g but also on possible input arguments. Is my understanding correct? Is there any documentation or explanation on the implementation of ≗? I found the implementation in the standard library to be undocumented and rather intricate, split across several files and using multiple levels of abstraction.
(Is there any way to conventiently browse the standard library except for browsing the source code (e.g., via grep or clicking in Github)?)
No there isn't.
That's correct. The definition of ≗ is a bit involved because it reuses existing notion but you can ask Agda to normalise it (C-c C-n in emacs) and see that it's just:
λ {A} {B} f g → (x : A) → f x ≡ g x
I typically use http://agda.github.io/agda-stdlib/

Parametric theorem implied by goal

During some development using cubical-agda, I noticed (and later checked) that my current goal, if proven would also imply such theorem:
parametric? : ∀ ℓ → Type (ℓ-suc ℓ)
parametric? ℓ = (f : {A : Type ℓ} → List A ≃ List A)
→ (A : Type ℓ) → length ∘ equivFun (f {A}) ≡ length
I suspect that this is example of parametric theorem, which is true, but is unprovable in cubical agda. Is it the case?
Can I safely assume that my current goal is also unprovable?
Yes, because it's false in the standard (simplicial sets) model.
If excluded middle holds, we can define f : {A : Type ℓ} → List A ≃ List A by first doing a case analysis on whether A is contractible or not. If A is not contractible, f gives the identity equivalence, but if A is contractible, then List A is equivalent to Nat, and, f can give an equivalence that, e.g., permutes odds and evens.

Agda: rewriting instead of explicit coercion in type definition?

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.

Is it possible to get hold of free theorems as propositional equalities?

"Free theorems" in the sense of Wadler's paper "Theorems for Free!" are equations about certain values are derived based only on their type. So that, for example,
f : {A : Set} → List A → List A
automatically satisfies
f . map g = map g . f
Can I get my hands on an Agda term, then, of the following type:
(f : {A : Set} → List A → List A) {B C : Set} (g : B → C) (xs : List B)
→ f (map g xs) ≡ map g (f xs)
or if so/if not, can I do something more/less general?
I'm aware of the existence of the Lightweight Free Theorems library but I don't think it does what I want (or if it does, I don't understand it well enough to do it).
(An example use case is that I have a functor F : Set → Set and would like to prove that a polymorphic function F A × F B → F (A × B) is automatically a natural transformation.)
No, the type theory on which Agda is build is not strong enough to prove this. This would require a feature called "internalized parametricity", see the work by Guilhem:
Jean-Philippe Bernardy and Guilhem Moulin: A Computational Interpretation of Parametricity (2012)
Guilhem Moulin: Pure Type Systems with an Internalized Parametricity Theorem (2013)
This would allow you for example to prove that all inhabitants of "(A : Set) → A → A" are equal to the (polymorphic) identity function. As far as I know, this has not been implemented in any language yet.
Chantal Keller and Marc Lasson developped a tactic for Coq generating the parametricity relation corresponding to a (closed) type and proving that this type's inhabitants satisfy the generated relation. You can find more details about this work on Keller's website.
Now in Agda's case, it is in theory possible to do the same sort of work by implementing the tactic in pure Agda using a technique called reflection.

Using multiple EqReasoning instantiations conveniently

Is there a way to conveniently use multiple instantiations of EqReasoning where the underlying Setoid is not necessarily semantic equality (i.e. ≡-Reasoning cannot be used)? The reason that ≡-Reasoning is convenient is that the type argument is implicit and it uniquely determines the Setoid in use by automatically selecting semantic equality. When using arbitrary Setoids there is no such unique selection. However a number of structures provide a canonical way to lift a Setoid:
Data.Maybe and Data.Covec have a setoid member.
Data.Vec.Equality.Equality provides enough definitions to write a canonical Setoid lifting for Vec as well. Interestingly there is also is a slightly different equality available at Relation.Binary.Vec.Pointwise, but it does not provide a direct lifting either albeit implementing all the necessary bits.
Data.List ships a Setoid lifting in Relation.Binary.List.Pointwise.
Data.Container also knows how to lift a Setoid.
By using any of these structures, one automatically gets to work with multiple Setoids even if one started out with one. When proofs use these structures (multiple of them in a single proof), it becomes difficult to write down the proof, because EqReasoning must be instantiated for all of them even though each particular Setoid is kind of obvious. This can be done by renaming begin_, _≈⟨_⟩_ and _∎, but I don't consider this renaming convenient.
Consider for example, a proof in the Setoid of Maybe where a sequence of arguments needs to be wrapped in Data.Maybe.Eq.just (think cong just) or a proof in an arbitrary Setoid that temporarily needs to wrap things in a just constructor exploiting its injectivity.
Normally, the only way Agda can pick something for you is when it is uniquely determined by the context. In the case of EqReasoning, there isn't usually enough information to pin down the Setoid, even worse actually: you could have two different Setoids over the same Carrier and _≈_ (consider for example two definitionally unequal proofs of transitivity in the isEquivalence field).
However, Agda does allow special form of implicit arguments, which can be filled as long as there is only one value of the desired type. These are known as instance arguments (think instance as in Haskell type class instances).
To demonstrate roughly how this works:
postulate
A : Set
a : A
Now, instance arguments are wrapped in double curly braces {{}}:
elem : {{x : A}} → A
elem {{x}} = x
If we decide to later use elem somewhere, Agda will check for any values of type A in scope and if there's only one of them, it'll fill that one in for {{x : A}}. If we added:
postulate
b : A
Agda will now complain that:
Resolve instance argument _x_7 : A. Candidates: [a : A, b : A]
Because Agda already allows you to perform computations on type level, instance arguments are deliberately limited in what they can do, namely Agda won't perform recursive search to fill them in. Consider for example:
eq : ... → IsEquivalence _≈_ → IsEquivalence (Eq _≈_)
where Eq is Data.Maybe.Eq mentioned in your question. When you then require Agda to fill in an instance argument of a type IsEquivalence (Eq _≈_), it won't try to find something of type IsEquivalence _≈_ and apply eq to it.
With that out of the way, let's take a look at what could work. However, bear in mind that all this stands on unification and as such you might need to push it in the right direction here and there (and if the types you are dealing with become complex, unification might require you to give it so many directions that it won't be worth it in the end).
Personally, I find instance arguments a bit fragile and I usually avoid them (and from a quick check, it would seem that so does the standard library), but your experience might vary.
Anyways, here we go. I constructed a (totally nonsensical) example to demonstrate how to do it. Some boilerplate first:
open import Data.Maybe
open import Data.Nat
open import Relation.Binary
import Relation.Binary.EqReasoning as EqR
To make this example self-contained, I wrote some kind of Setoid with natural numbers as its carrier:
data _≡ℕ_ : ℕ → ℕ → Set where
z≡z : 0 ≡ℕ 0
s≡s : ∀ {m n} → m ≡ℕ n → suc m ≡ℕ suc n
ℕ-setoid : Setoid _ _
ℕ-setoid = record
{ _≈_ = _≡ℕ_
; isEquivalence = record
{ refl = refl
; sym = sym
; trans = trans
}
}
where
refl : Reflexive _≡ℕ_
refl {zero} = z≡z
refl {suc _} = s≡s refl
sym : Symmetric _≡ℕ_
sym z≡z = z≡z
sym (s≡s p) = s≡s (sym p)
trans : Transitive _≡ℕ_
trans z≡z q = q
trans (s≡s p) (s≡s q) = s≡s (trans p q)
Now, the EqReasoning module is parametrized over a Setoid, so usually you do something like this:
open EqR ℕ-setoid
However, we'd like to have the Setoid parameter to be implicit (instance) rather than explicit, so we define and open a dummy module:
open module Dummy {c ℓ} {{s : Setoid c ℓ}} = EqR s
And we can write this simple proof:
idʳ : ∀ n → n ≡ℕ (n + 0)
idʳ 0 = z≡z
idʳ (suc n) = begin
suc n ≈⟨ s≡s (idʳ n) ⟩
suc (n + 0) ∎
Notice that we never had to specify ℕ-setoid, the instance argument picked it up because it was the only type-correct value.
Now, let's spice it up a bit. We'll add Data.Maybe.setoid into the mix. Again, because instance arguments do not perform a recursive search, we'll have to define the setoid ourselves:
Maybeℕ-setoid = setoid ℕ-setoid
_≡M_ = Setoid._≈_ Maybeℕ-setoid
I'm going to postulate few stupid things just to demonstrate that Agda indeed picks correct setoids:
postulate
comm : ∀ m n → (m + n) ≡ℕ (n + m)
eq0 : ∀ n → n ≡ℕ 0
eq∅ : just 0 ≡M nothing
lem : ∀ n → just (n + 0) ≡M nothing
lem n = begin
just (n + 0) ≈⟨ just
(begin
n + 0 ≈⟨ comm n 0 ⟩
n ≈⟨ eq0 n ⟩
0 ∎
)⟩
just 0 ≈⟨ eq∅ ⟩
nothing ∎
I figured an alternative to the proposed solution using instance arguments that slightly bends the requirements, but fits my purpose. The major burden in the question was having to explicitly open EqReasoning multiple times and especially having to invent new names for the contained symbols. A slight improvement would be to pass the correct Setoid once per relation proof. In other words passing it to begin_ or _∎ somehow. Then we could make the Setoid implicit for all the other functions!
import Relation.Binary.EqReasoning as EqR
import Relation.Binary using (Setoid)
module ExplicitEqR where
infix 1 begin⟨_⟩_
infixr 2 _≈⟨_⟩_ _≡⟨_⟩_
infix 2 _∎
begin⟨_⟩_ : ∀ {c l} (X : Setoid c l) → {x y : Setoid.Carrier X} → EqR._IsRelatedTo_ X x y → Setoid._≈_ X x y
begin⟨_⟩_ X p = EqR.begin_ X p
_∎ : ∀ {c l} {X : Setoid c l} → (x : Setoid.Carrier X) → EqR._IsRelatedTo_ X x x
_∎ {X = X} = EqR._∎ X
_≈⟨_⟩_ : ∀ {c l} {X : Setoid c l} → (x : Setoid.Carrier X) → {y z : Setoid.Carrier X} → Setoid._≈_ X x y → EqR._IsRelatedTo_ X y z → EqR._IsRelatedTo_ X x z
_≈⟨_⟩_ {X = X} = EqR._≈⟨_⟩_ X
_≡⟨_⟩_ : ∀ {c l} {X : Setoid c l} → (x : Setoid.Carrier X) → {y z : Setoid.Carrier X} → x ≡ y → EqR._IsRelatedTo_ X y z → EqR._IsRelatedTo_ X x z
_≡⟨_⟩_ {X = X} = EqR._≡⟨_⟩_ X
Reusing the nice example from Vitus answer, we can write it:
lem : ∀ n → just (n + 0) ≡M nothing
lem n = begin⟨ Data.Maybe.setoid ℕ-setoid ⟩
just (n + 0) ≈⟨ just
(begin⟨ ℕ-setoid ⟩
n + 0 ≈⟨ comm n 0 ⟩
n ≈⟨ eq0 n ⟩
0 ∎
)⟩
just 0 ≈⟨ eq∅ ⟩
nothing ∎
where open ExplicitEqR
One still has to mention the Setoids in use, to avoid the use of instance arguments as presented by Vitus. However the technique makes it significantly more convenient.

Resources