Decidable equality of data types in Agda - agda

I am trying to prove decidable equality of a data type in Agda using the Agda stdlib. I have the following code, but I am unsure what to fill in the hole. The goal seems to make sense, but actually constructing it is challenging.
Is this possible in Agda and are there any ideas on how to solve this?
open import Data.String as String hiding (_≟_)
open import Relation.Nullary
open import Relation.Binary
open import Relation.Binary.PropositionalEquality
module Problem1 where
data Test : Set where
test : String → Test
infix 4 _≟_
_≟_ : Decidable {A = Test} _≡_
test x ≟ test x₁ with x String.≟ x₁
... | yes refl = yes refl
... | no ¬a = no {!!}
The hole:
Goal: ¬ test x ≡ test x₁
————————————————————————————————————————————————————————————
¬a : ¬ x ≡ x₁
x₁ : ℕ
x : ℕ

This is actually a one liner, relying on case splitting over the equality proof inside an anonymous function, as follows:
... | no ¬a = no λ {refl → ¬a refl}

Related

Is it possible to prove not equals is irrelevant without funext?

I can trivially prove that not equals is irrelevant with function extensionality:
open import Relation.Binary.PropositionalEquality using (_≢_)
open import Relation.Binary using (Irrelevant)
open import Relation.Nullary.Negation using (contradiction)
open import Axiom.Extensionality.Propositional using (Extensionality)
postulate
fun-ext : ∀ {ℓ₁ ℓ₂} → Extensionality ℓ₁ ℓ₂
≢-irrelevant : ∀ {a} {A : Set a} → Irrelevant {A = A} _≢_
≢-irrelevant {x} {y} [x≉y]₁ [x≉y]₂ = fun-ext (λ x≈y → contradiction x≈y [x≉y]₁)
This seems impossible to prove without funext when A is polymorphic but is it possible when A = ℕ or A = Bool?
This is not provable without funext. We did consider changing the definition of the empty type to make these provable however it was deemed too invasive a change.

Representing homomorphisms without writing all laws out

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.

With-abstraction and equality

In the following example
open import Agda.Builtin.Nat
open import Agda.Builtin.Equality
postulate
f : Nat → Nat
g : ∀{x y} → f x ≡ suc y → Nat
h : Nat → Nat
h x with f x
h x | zero = zero
h x | suc y = g {x} {y} {!refl!}
Agda doesn't accept refl for an argument.
The main questions are,
what am I doing wrong?
what is the correct/optimal/established/preferred way of proving stuff like this?
And of course any insights into Agda's behavior are greatly appreciated.
≡-Reasoning and 'with' patterns and Agda: type isn't simplified in with block should answer your questions. The official docs describe how to do what you want, but they don't seem to be too beginner-friendly.

Parametricity-exploiting proofs in 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

Is there any non-trivial code that uses Data.Maybe.Is-just?

The Agda standard library provides a data type Maybe accompanied with a view Any.
Then there is the property Is-just defined using Any. I found working with this type difficult as the standard library provides exactly no tooling for Any.
Thus I am looking for examples on how to work with Is-just effectively. Is there an open source project that uses it?
Alternatively, I am seeking how to put it to good use:
Given Is-just m and Is-nothing m, how to eliminate? Can Relation.Nullary.Negation.contradiction be used here?
Given a property p : ... → (mp : Is-just m) → ... → ... ≡ to-witness mp that needs to be shown inductively by p ... = {! p ... (subst Is-just m≡somethingelse mp) ... !}, the given term does not fill the hole, because it has type ... ≡ to-witness (subst Is-just m≡somethingelse mp).
Often it seems easier to work with Σ A (_≡_ m ∘ just) than Is-just m.
Regarding your first question, it is possible to derive a contradiction from having both Is-just m and Is-nothing m in context. You can then use ⊥-elim to prove anything.
module isJust where
open import Level
open import Data.Empty
open import Data.Maybe
contradiction :
{ℓ : Level} {A : Set ℓ} {m : Maybe A}
(j : Is-just m) (n : Is-nothing m) → ⊥
contradiction (just _) (just pr) = pr
The second one is a bit too abstract for me to be sure whether what I'm suggesting will work but the usual strategies are to try to pattern match on the value of type Maybe A or on the proof that Is-just m.
As for using another definition of Is-just, I tend to like
open import Data.Bool
isJust : {ℓ : Level} {A : Set ℓ} (m : Maybe A) → Set
isJust m = T (is-just m)
because it computes.

Resources