With the following definition of equality, we have refl as constructor
data _≡_ {a} {A : Set a} (x : A) : A → Set a where
refl : x ≡ x
and we can prove that function are congruent on equality
cong : ∀ { a b} { A : Set a } { B : Set b }
(f : A → B ) {m n} → m ≡ n → f m ≡ f n
cong f refl = refl
I am not sure I can parse what is going on exactly here. I think we are pattern matching refl on hidden parameters : if we replace the first occurence by refl by another identifier, we get a type error. after pattern matching, I imagine that m and n are the same by the definition of refl. then magic occurs (a definition of functionality of a relation is applied ? or is it build in ?)
Is there an intuitive description on what is going on ?
Yes, the arguments in curly braces
{}
are implicit and they only need to be supplied or matched if agda cannot figure them out. It is necessary to specify them, since dependent types needs to refer to the values they depend on, but dragging them around all the time would make the code rather clunky.The expression
cong f refl = refl
matches the explicit arguments (A → B
) and (m ≡ n
). If you wanted to match the implicit arguments, you'd need to put the matching expression in{}
, but here there is no need for that. Then on the right hand side it is indeed the construction of (f m ≡ f n
) usingrefl
, and it works "by magic". Agda has a built-in axiom that proves this to be true. That axiom is similar (but stronger than)J
-axiom - the induction axiom: if somethingC : (x y : A) → (x ≡ y) → Set
is true forC x x refl
, then it is also true for anyx y : A
andp : x ≡ y
.(In this last line we: match explicit arguments
f
andp
, and also the implicit argumentsm=x
andn=y
. Then we pass toJ
one implicit argument, but it is not the first positional implicit, so we tell agda that it isC
in the definition - without doing that, Agda won't see what type is meant byrefl
in\_ → refl
)