The answer depends on what you call a set. If by set you mean a representation of the mathematical sets, such as a list, then the empty set is just represented by the empty list.
If by set you mean the Agda Set
which means a type, then the answer is a bit more complicated: there is not an empty type, but there are as many as you can think of. More precisely, there are as many empty types as data types for which you don't provide any constructor. The question is then more "which of these types do I chose to model the empty set ?" rather than "how do I model the empty set ?".
Here is an example of an agda module which emphasizes this aspect: First, I have a few imports and the header of my module:
open import Agda.Primitive
open import Data.Nat hiding (_⊔_)
module EmptySets where
Then I start by an empty type, the more simple you can think of:
data Empty : Set where
From this data type, it is possible to write an eliminator:
Empty-elim : ∀ {a} {A : Set a} → Empty → A
Empty-elim ()
This basically says that anything holds if Empty
holds.
But, I could have also chosen to represent the empty set as the empty relation by defining a family of types, all empty, which are all relations. First, relations needs to be defined (I took the definition from the standard library):
REL : ∀ {a b} → Set a → Set b → (ℓ : Level) → Set (a ⊔ b ⊔ lsuc ℓ)
REL A B ℓ = A → B → Set ℓ
Then the family of empty relations can be defined :
data EmptyRelation {a b ℓ} {A : Set a} {B : Set b} : REL A B ℓ where
Since all these types are empty, they all provide an eliminator as well:
EmptyRelation-elim : ∀ {a b x ℓ} {A : Set a} {B : Set b} {X : Set x} {u : A} {v : B} → EmptyRelation {ℓ = ℓ} u v → X
EmptyRelation-elim ()
And, as a consequence, it is possible to instantiate this generic type to get a specific empty type, for instance, the empty relation over natural numbers, which never holds:
EmptyNaturalRelation : REL ℕ ℕ lzero
EmptyNaturalRelation = EmptyRelation
This is what is explained in the book: since a relation is a set of pairs, then the empty type is the smallest of this relation: the one where there are no pairs in it.
But you could also use predicates instead of relations, saying that the empty set is the smallest predicate over a given type: the one that never holds, in which case this is represented as the following:
Pred : ∀ {a} → Set a → (ℓ : Level) → Set (a ⊔ lsuc ℓ)
Pred A ℓ = A → Set ℓ
data EmptyPredicate {a ℓ} {A : Set a} : Pred A ℓ where
And you could be even crazier and decide to model the empty set as the following:
data EmptySomething {a} {A B C D E Z : Set a} : A → B → C → D → E → Z → Set where
All in all, there are no empty set in agda, but there are a potential infinity of empty types.
As for the code you presented in your question, there are several inaccuracies:
The relations are usually defined on two arguments instead of pairs of argument, which you can then curry on if needed to make them take a pair as parameter.
Why would you make lteℕ
depend on _≤ℕ_
and not define it directly ?
You should define lteℕ
as a data type rather than a function which returns either bottom or top, which will allow you to case-split on such a term in the future. Usually, this is defined this way (in the standard library):
data _≤_ : Rel ℕ 0ℓ where
z≤n : ∀ {n} → zero ≤ n
s≤s : ∀ {m n} (m≤n : m ≤ n) → suc m ≤ suc n
data ∅ : Set where
which is the unhabited type. I understand the triviality of the definition, but that means that the empty set is a relation between any two sets, isn't it? Therefore, I would expect to be able to say that the empty set has typeØ : Relation Set
. No? – Raoul