Considering the following agda module signature:
module EqList {a ℓ} {A : Set a} {_≈_ : Rel A ℓ} (eq≈ : IsEquivalence _≈_) where
We can define the membership in a list, the list inclusion and the list equivalence:
_∈_ : REL A (List A) _
_∈_ x = Any (x ≈_)
_⊑_ : Rel (List A) _
_⊑_ = _⊆_ on flip _∈_
_≋_ : Rel (List A) _
_≋_ = _⊑_ -[ _×_ ]- flip _⊑_
We can then proceed to prove that this last relation is indeed an equivalence relation:
isEq≋ : IsEquivalence _≋_
isEq≋ = record {
refl = id , id ;
sym = swap ;
trans = zip (λ f g → g ∘ f) λ f g → f ∘ g }
The proof of transitivity is what makes my question arise. The previous definition is accepted by Agda while the following is rejected:
trans = zip (flip _∘_) _∘_
The error is as follows:
({x : A} → Any (_≈_ x) i → Any (_≈_ x) j) !=
((x : A) → Any (_≈_ x) j) because one is an implicit function type
and the other is an explicit function type
when checking that the expression _∘_ has type
(x : j ⊑ k) (y : i ⊑ j) → i ⊑ k
While this error feels weird, because both proofs should be equivalent (replacing the expression f
by the expression λ x → f x
should always yield the same result) I can somewhat understand why it behaves this way : there is intern trouble as to how to instantiate the various implicit arguments of _∘_
. But this explanation is only intuitive and not very conclusive, so my question is the following:
Can someone explain in details why the typechecker succeeds in the first case and not in the second ?
As a side note, here is the header of the module, in order for this example to be self contained:
open import Relation.Binary.Core
open import Data.List hiding (zip)
open import Data.List.Any
open import Relation.Unary using (_⊆_)
open import Function
open import Data.Product
As a second side note, I am aware that a similar question has already been answered:
How to get around the implicit vs explicit function type error?
But said answer does not contain any deep explanation about this surprising behavior.