update Lists, Decidable and reorganise files

This commit is contained in:
wadler 2018-03-22 18:46:29 -03:00
parent b943785e6b
commit fb3592239d
7 changed files with 31 additions and 1211 deletions

View file

@ -1,817 +0,0 @@
---
title : "Connectives: Conjunction, Disjunction, and Implication"
layout : page
permalink : /Connectives
---
This chapter introduces the basic logical connectives, by observing
a correspondence between connectives of logic and data types,
a principal known as *Propositions as Types*.
+ *conjunction* is *product*
+ *disjunction* is *sum*
+ *true* is *unit type*
+ *false* is *empty type*
+ *implication* is *function space*
## Imports
\begin{code}
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong)
open Eq.≡-Reasoning
open import Isomorphism using (_≃_; ≃-sym; ≃-trans; _≲_)
open Isomorphism.≃-Reasoning
open import Data.Nat using (; zero; suc; _+_; _*_)
open import Data.Nat.Properties.Simple using (+-suc)
open import Function using (_∘_)
\end{code}
We assume [extensionality][extensionality].
\begin{code}
postulate
extensionality : ∀ {A B : Set} {f g : A → B} → (∀ (x : A) → f x ≡ g x) → f ≡ g
\end{code}
[extensionality]: Equality/index.html#extensionality
## Conjunction is product
Given two propositions `A` and `B`, the conjunction `A × B` holds
if both `A` holds and `B` holds. We formalise this idea by
declaring a suitable inductive type.
\begin{code}
data _×_ : Set → Set → Set where
_,_ : ∀ {A B : Set} → A → B → A × B
\end{code}
Evidence that `A × B` holds is of the form
`(M , N)`, where `M` is evidence that `A` holds and
`N` is evidence that `B` holds. By convention, we
parenthesise pairs, even though `M , N` is also
accepted by Agda.
Given evidence that `A × B` holds, we can conclude that either
`A` holds or `B` holds.
\begin{code}
proj₁ : ∀ {A B : Set} → A × B → A
proj₁ (x , y) = x
proj₂ : ∀ {A B : Set} → A × B → B
proj₂ (x , y) = y
\end{code}
If `L` is evidence that `A × B` holds, then `fst L` is evidence
that `A` holds, and `proj₂ L` is evidence that `B` holds.
Equivalently, we could also declare conjunction as a record type.
\begin{code}
record _×_ (A B : Set) : Set where
field
proj₁ : A
proj₂ : B
open _×_
\end{code}
Here record construction
record
{ proj₁ = M
; proj₂ = N
}
corresponds to the term
( M , N )
where `M` is a term of type `A` and `N` is a term of type `B`.
When `(_,_)` appears on the right-hand side of an equation we
refer to it as a *constructor*, and when it appears on the
left-hand side we refer to it as a *destructor*. We also refer
to `proj₁` and `proj₂` as destructors, since they play a similar role.
Other terminology refers to constructor as *introducing* a conjunction,
and to a destructor as *eliminating* a conjunction.
Indeed, `proj₁` and `proj₂` are sometimes given the names
`×-elim₁` and `×-elim₂`.
Applying each destructor and reassembling the results with the
constructor is the identity over products.
\begin{code}
η-× : ∀ {A B : Set} (w : A × B) → (proj₁ w , proj₂ w) ≡ w
η-× (x , y) = refl
\end{code}
The pattern matching on the left-hand side is essential, since
replacing `w` by `(x , y)` allows both sides of the equation to
simplify to the same term.
We set the precedence of conjunction so that it binds less
tightly than anything save disjunction, and of the pairing
operator so that it binds less tightly than any arithmetic
operator.
\begin{code}
infixr 2 _×_
infixr 4 _,_
\end{code}
Thus, `m ≤ n × n ≤ p` parses as `(m ≤ n) × (n ≤ p)` and
`(m * n , p)` parses as `((m * n) , p)`.
Given two types `A` and `B`, we refer to `A x B` as the
*product* of `A` and `B`. In set theory, it is also sometimes
called the *cartesian product*, and in computing it corresponds
to a *record* type. Among other reasons for
calling it the product, note that if type `A` has `m`
distinct members, and type `B` has `n` distinct members,
then the type `A × B` has `m * n` distinct members.
For instance, consider a type `Bool` with two members, and
a type `Tri` with three members.
\begin{code}
data Bool : Set where
true : Bool
false : Bool
data Tri : Set where
aa : Tri
bb : Tri
cc : Tri
\end{code}
Then the type `Bool × Tri` has six members:
(true , aa) (true , bb) (true , cc)
(false , aa) (false , bb) (false , cc)
For example, the following function enumerates all
possible arguments of type `Bool × Tri`:
\begin{code}
×-count : Bool × Tri →
×-count (true , aa) = 1
×-count (true , bb) = 2
×-count (true , cc) = 3
×-count (false , aa) = 4
×-count (false , bb) = 5
×-count (false , cc) = 6
\end{code}
Product on types also shares a property with product on numbers in
that there is a sense in which it is commutative and associative. In
particular, product is commutative and associative *up to
isomorphism*.
For commutativity, the `to` function swaps a pair, taking `(x , y)` to
`(y , x)`, and the `from` function does the same (up to renaming).
Instantiating the patterns correctly in `from∘to` and `to∘from` is essential.
Replacing the definition of `from∘to` by `λ w → refl` will not work;
and similarly for `to∘from`, which does the same (up to renaming).
\begin{code}
×-comm : ∀ {A B : Set} → (A × B) ≃ (B × A)
×-comm =
record
{ to = λ{ (x , y) → (y , x)}
; from = λ{ (y , x) → (x , y)}
; from∘to = λ{ (x , y) → refl }
; to∘from = λ{ (y , x) → refl }
}
\end{code}
Being *commutative* is different from being *commutative up to
isomorphism*. Compare the two statements:
m * n ≡ n * m
A × B ≃ B × A
In the first case, we might have that `m` is `2` and `n` is `3`, and
both `m * n` and `n * m` are equal to `6`. In the second case, we
might have that `A` is `Bool` and `B` is `Tri`, and `Bool × Tri` is
*not* the same as `Tri × Bool`. But there is an isomorphism
between the two types. For
instance, `(true , aa)`, which is a member of the former, corresponds
to `(aa , true)`, which is a member of the latter.
For associativity, the `to` function reassociates two uses of pairing,
taking `((x , y) , z)` to `(x , (y , z))`, and the `from` function does
the inverse. Again, the evidence of left and right inverse requires
matching against a suitable pattern to enable simplification.
\begin{code}
×-assoc : ∀ {A B C : Set} → ((A × B) × C) ≃ (A × (B × C))
×-assoc =
record
{ to = λ{ ((x , y) , z) → (x , (y , z)) }
; from = λ{ (x , (y , z)) → ((x , y) , z) }
; from∘to = λ{ ((x , y) , z) → refl }
; to∘from = λ{ (x , (y , z)) → refl }
}
\end{code}
Being *associative* is not the same as being *associative
up to isomorphism*. Compare the two statements:
(m * n) * p ≡ m * (n * p)
(A × B) × C ≃ A × (B × C)
For example, the type `( × Bool) × Tri` is *not* the same as ` ×
(Bool × Tri)`. But there is an isomorphism between the two types. For
instance `((1 , true) , aa)`, which is a member of the former,
corresponds to `(1 , (true , aa))`, which is a member of the latter.
## Truth is unit
Truth `` always holds. We formalise this idea by
declaring a suitable inductive type.
\begin{code}
data : Set where
tt :
\end{code}
Evidence that `` holds is of the form `tt`.
Given evidence that `` holds, there is nothing more of interest we
can conclude. Since truth always holds, knowing that it holds tells
us nothing new.
The nullary case of `η-×` is `η-`, which asserts that any
term of type `` must be equal to `tt`.
\begin{code}
η- : ∀ (w : ) → tt ≡ w
η- tt = refl
\end{code}
The pattern matching on the left-hand side is essential. Replacing
`w` by `tt` allows both sides of the equation to simplify to the
same term.
We refer to `` as the *unit* type. And, indeed,
type `` has exactly once member, `tt`. For example, the following
function enumerates all possible arguments of type ``:
\begin{code}
-count :
-count tt = 1
\end{code}
For numbers, one is the identity of multiplication. Correspondingly,
unit is the identity of product *up to isomorphism*. For left
identity, the `to` function takes `(tt , x)` to `x`, and the `from`
function does the inverse. The evidence of left inverse requires
matching against a suitable pattern to enable simplification.
\begin{code}
-identityˡ : ∀ {A : Set} → ( × A) ≃ A
-identityˡ =
record
{ to = λ{ (tt , x) → x }
; from = λ{ x → (tt , x) }
; from∘to = λ{ (tt , x) → refl }
; to∘from = λ{ x → refl }
}
\end{code}
Having an *identity* is different from having an identity
*up to isomorphism*. Compare the two statements:
1 * m ≡ m
× A ≃ A
In the first case, we might have that `m` is `2`, and both
`1 * m` and `m` are equal to `2`. In the second
case, we might have that `A` is `Bool`, and ` × Bool` is *not* the
same as `Bool`. But there is an isomorphism between the two types.
For instance, `(tt, true)`, which is a member of the former,
corresponds to `true`, which is a member of the latter.
Right identity follows from commutativity of product and left identity.
\begin{code}
-identityʳ : ∀ {A : Set} → (A × ) ≃ A
-identityʳ {A} =
≃-begin
(A × )
≃⟨ ×-comm ⟩
( × A)
≃⟨ -identityˡ ⟩
A
≃-∎
\end{code}
Here we have used a chain of isomorphisms,
analogous to that used for equality.
## Disjunction is sum
Given two propositions `A` and `B`, the disjunction `A ⊎ B` holds
if either `A` holds or `B` holds. We formalise this idea by
declaring a suitable inductive type.
\begin{code}
data _⊎_ : Set → Set → Set where
inj₁ : ∀ {A B : Set} → A → A ⊎ B
inj₂ : ∀ {A B : Set} → B → A ⊎ B
\end{code}
Evidence that `A ⊎ B` holds is either of the form `inj₁ M`, where `M`
is evidence that `A` holds, or `inj₂ N`, where `N` is evidence that
`B` holds.
Given evidence that `A → C` and `B → C` both hold, then given
evidence that `A ⊎ B` holds we can conclude that `C` holds.
\begin{code}
⊎-elim : ∀ {A B C : Set} → (A → C) → (B → C) → (A ⊎ B → C)
⊎-elim f g (inj₁ x) = f x
⊎-elim f g (inj₂ y) = g y
\end{code}
Pattern matching against `inj₁` and `inj₂` is typical of how we exploit
evidence that a disjunction holds.
When `inj₁` and `inj₂` appear on the right-hand side of an equation we
refer to them as *constructors*, and when they appears on the
left-hand side we refer to them as *destructors*. We also refer
to `⊎-elim` as a destructor, since it plays a similar role.
Other terminology refers to constructors as *introducing* a disjunction,
and to a destructors as *eliminating* a disjunction.
Applying the destructor to each of the constructors is the identity.
\begin{code}
η-⊎ : ∀ {A B : Set} (w : A ⊎ B) → ⊎-elim inj₁ inj₂ w ≡ w
η-⊎ (inj₁ x) = refl
η-⊎ (inj₂ y) = refl
\end{code}
More generally, we can also throw in an arbitrary function from a disjunction.
\begin{code}
uniq-⊎ : ∀ {A B C : Set} (h : A ⊎ B → C) (w : A ⊎ B) →
⊎-elim (h ∘ inj₁) (h ∘ inj₂) w ≡ h w
uniq-⊎ h (inj₁ x) = refl
uniq-⊎ h (inj₂ y) = refl
\end{code}
The pattern matching on the left-hand side is essential. Replacing
`w` by `inj₁ x` allows both sides of the equation to simplify to the
same term, and similarly for `inj₂ y`.
We set the precedence of disjunction so that it binds less tightly
than any other declared operator.
\begin{code}
infix 1 _⊎_
\end{code}
Thus, `A × C ⊎ B × C` parses as `(A × C) ⊎ (B × C)`.
Given two types `A` and `B`, we refer to `A ⊎ B` as the
*sum* of `A` and `B`. In set theory, it is also sometimes
called the *disjoint union*, and in computing it corresponds
to a *variant record* type. Among other reasons for
calling it the sum, note that if type `A` has `m`
distinct members, and type `B` has `n` distinct members,
then the type `A ⊎ B` has `m + n` distinct members.
For instance, consider a type `Bool` with two members, and
a type `Tri` with three members, as defined earlier.
Then the type `Bool ⊎ Tri` has five
members:
(inj₁ true) (inj₂ aa)
(inj₁ false) (inj₂ bb)
(inj₂ cc)
For example, the following function enumerates all
possible arguments of type `Bool ⊎ Tri`:
\begin{code}
⊎-count : Bool ⊎ Tri →
⊎-count (inj₁ true) = 1
⊎-count (inj₁ false) = 2
⊎-count (inj₂ aa) = 3
⊎-count (inj₂ bb) = 4
⊎-count (inj₂ cc) = 5
\end{code}
Sum on types also shares a property with sum on numbers in that it is
commutative and associative *up to isomorphism*.
For commutativity, the `to` function swaps the two constructors,
taking `inj₁ x` to `inj₂ x`, and `inj₂ y` to `inj₁ y`; and the `from`
function does the same (up to renaming). Replacing the definition of
`from∘to` by `λ w → refl` will not work; and similarly for `to∘from`, which
does the same (up to renaming).
\begin{code}
⊎-comm : ∀ {A B : Set} → (A ⊎ B) ≃ (B ⊎ A)
⊎-comm = record
{ to = λ{ (inj₁ x) → (inj₂ x)
; (inj₂ y) → (inj₁ y)
}
; from = λ{ (inj₁ y) → (inj₂ y)
; (inj₂ x) → (inj₁ x)
}
; from∘to = λ{ (inj₁ x) → refl
; (inj₂ y) → refl
}
; to∘from = λ{ (inj₁ y) → refl
; (inj₂ x) → refl
}
}
\end{code}
Being *commutative* is different from being *commutative up to
isomorphism*. Compare the two statements:
m + n ≡ n + m
A ⊎ B ≃ B ⊎ A
In the first case, we might have that `m` is `2` and `n` is `3`, and
both `m + n` and `n + m` are equal to `5`. In the second case, we
might have that `A` is `Bool` and `B` is `Tri`, and `Bool ⊎ Tri` is
*not* the same as `Tri ⊎ Bool`. But there is an isomorphism between
the two types. For instance, `inj₁ true`, which is a member of the
former, corresponds to `inj₂ true`, which is a member of the latter.
For associativity, the `to` function reassociates, and the `from` function does
the inverse. Again, the evidence of left and right inverse requires
matching against a suitable pattern to enable simplification.
\begin{code}
⊎-assoc : ∀ {A B C : Set} → ((A ⊎ B) ⊎ C) ≃ (A ⊎ (B ⊎ C))
⊎-assoc = record
{ to = λ{ (inj₁ (inj₁ x)) → (inj₁ x)
; (inj₁ (inj₂ y)) → (inj₂ (inj₁ y))
; (inj₂ z) → (inj₂ (inj₂ z))
}
; from = λ{ (inj₁ x) → (inj₁ (inj₁ x))
; (inj₂ (inj₁ y)) → (inj₁ (inj₂ y))
; (inj₂ (inj₂ z)) → (inj₂ z)
}
; from∘to = λ{ (inj₁ (inj₁ x)) → refl
; (inj₁ (inj₂ y)) → refl
; (inj₂ z) → refl
}
; to∘from = λ{ (inj₁ x) → refl
; (inj₂ (inj₁ y)) → refl
; (inj₂ (inj₂ z)) → refl
}
}
\end{code}
Again, being *associative* is not the same as being *associative
up to isomorphism*. For example, the type `( + Bool) + Tri`
is *not* the same as ` + (Bool + Tri)`. But there is an
isomorphism between the two types. For instance `inj₂ (inj₁ true)`,
which is a member of the former, corresponds to `inj₁ (inj₂ true)`,
which is a member of the latter.
## False is empty
False `⊥` never holds. We formalise this idea by declaring
a suitable inductive type.
\begin{code}
data ⊥ : Set where
-- no clauses!
\end{code}
There is no possible evidence that `⊥` holds.
Given evidence that `⊥` holds, we might conclude anything! Since
false never holds, knowing that it holds tells us we are in a
paradoxical situation. This is a basic principle of logic,
known in medieval times by the latin phrase *ex falso*,
and known to children through phrases such as
"if pigs had wings, then I'd be the Queen of Sheba".
We formalise it as follows.
\begin{code}
⊥-elim : ∀ {A : Set} → ⊥ → A
⊥-elim ()
\end{code}
This is our first use of the *absurd pattern* `()`.
Here since `⊥` is a type with no members, we indicate that it is
*never* possible to match against a value of this type by using
the pattern `()`.
The nullary case of `uniq-⊎` is `uniq-⊥`, which asserts that `⊥-elim`
is equal to any arbitrary function from `⊥`.
\begin{code}
uniq-⊥ : ∀ {C : Set} (h : ⊥ → C) (w : ⊥) → ⊥-elim w ≡ h w
uniq-⊥ h ()
\end{code}
The pattern matching on the left-hand side is essential. Using
the absurd pattern asserts there are no possible values for `w`,
so the equation holds trivially.
We refer to `⊥` as *empty* type. And, indeed,
type `⊥` has no members. For example, the following function
enumerates all possible arguments of type `⊥`:
\begin{code}
⊥-count : ⊥ →
⊥-count ()
\end{code}
Here again the absurd pattern `()` indicates that no value can match
type `⊥`.
For numbers, zero is the identity of addition. Correspondingly,
empty is the identity of sums *up to isomorphism*.
For left identity, the `to` function observes that `inj₁ ()` can never arise,
and takes `inj₂ x` to `x`, and the `from` function
does the inverse. The evidence of left inverse requires matching against
a suitable pattern to enable simplification.
\begin{code}
⊥-identityˡ : ∀ {A : Set} → (⊥ ⊎ A) ≃ A
⊥-identityˡ =
record
{ to = λ{ (inj₁ ())
; (inj₂ x) → x
}
; from = λ{ x → inj₂ x
}
; from∘to = λ{ (inj₁ ())
; (inj₂ x) → refl
}
; to∘from = λ{ x → refl
}
}
\end{code}
Having an *identity* is different from having an identity
*up to isomorphism*. Compare the two statements:
0 + m ≡ m
⊥ ⊎ A ≃ A
In the first case, we might have that `m` is `2`, and both `0 + m` and
`m` are equal to `2`. In the second case, we might have that `A` is
`Bool`, and `⊥ ⊎ Bool` is *not* the same as `Bool`. But there is an
isomorphism between the two types. For instance, `inj₂ true`, which is
a member of the former, corresponds to `true`, which is a member of
the latter.
Right identity follows from commutativity of sum and left identity.
\begin{code}
⊥-identityʳ : ∀ {A : Set} → (A ⊎ ⊥) ≃ A
⊥-identityʳ {A} =
≃-begin
(A ⊎ ⊥)
≃⟨ ⊎-comm ⟩
(⊥ ⊎ A)
≃⟨ ⊥-identityˡ ⟩
A
≃-∎
\end{code}
## Implication is function {#implication}
Given two propositions `A` and `B`, the implication `A → B` holds if
whenever `A` holds then `B` must also hold. We formalise implication using
the function type, which has appeared throughout this book.
Evidence that `A → B` holds is of the form
λ (x : A) → N x
where `N x` is a term of type `B` containing as a free variable `x` of type `A`.
Given a term `L` providing evidence that `A → B` holds, and a term `M`
providing evidence that `A` holds, the term `L M` provides evidence that
`B` holds. In other words, evidence that `A → B` holds is a function that
converts evidence that `A` holds into evidence that `B` holds.
Put another way, if we know that `A → B` and `A` both hold,
then we may conclude that `B` holds.
\begin{code}
→-elim : ∀ {A B : Set} → (A → B) → A → B
→-elim L M = L M
\end{code}
In medieval times, this rule was known by the name *modus ponens*.
It corresponds to function application.
Defining a function, with an named definition or a lambda expression,
is referred to as *introducing* a function,
while applying a function is referred to as *eliminating* the function.
Elimination followed by introduction is the identity.
\begin{code}
η-→ : ∀ {A B : Set} (f : A → B) → (λ (x : A) → f x) ≡ f
η-→ {A} {B} f = extensionality η-helper
where
η-helper : (x : A) → (λ (x : A) → f x) x ≡ f x
η-helper x = refl
\end{code}
The proof depends on extensionality.
<!--
If we introduce an implication and then immediately eliminate it, we can
always simplify the resulting term. Thus
λ{ x → N } M
simplifies to `N[x := M]`, where `N[x := M]` stands for the term `N` with each
free occurrence of `x` replaced by `M`.
-->
Implication binds less tightly than any other operator. Thus, `A ⊎ B →
B ⊎ A` parses as `(A ⊎ B) → (B ⊎ A)`.
Given two types `A` and `B`, we refer to `A → B` as the *function*
space from `A` to `B`. It is also sometimes called the *exponential*,
with `B` raised to the `A` power. Among other reasons for calling
it the exponential, note that if type `A` has `m` distinct
members, and type `B` has `n` distinct members, then the type
`A → B` has `n ^ m` distinct members. For instance, consider a
type `Bool` with two members and a type `Tri` with three members,
as defined earlier. The the type `Bool → Tri` has nine (that is,
three squared) members:
λ{true → aa; false → aa} λ{true → aa; false → bb} λ{true → aa; false → cc}
λ{true → bb; false → aa} λ{true → bb; false → bb} λ{true → bb; false → cc}
λ{true → cc; false → aa} λ{true → cc; false → bb} λ{true → cc; false → cc}
For example, the following function enumerates all possible
arguments of the type `Bool → Tri`:
\begin{code}
→-count : (Bool → Tri) →
→-count f with f true | f false
... | aa | aa = 1
... | aa | bb = 2
... | aa | cc = 3
... | bb | aa = 4
... | bb | bb = 5
... | bb | cc = 6
... | cc | aa = 7
... | cc | bb = 8
... | cc | cc = 9
\end{code}
Exponential on types also share a property with exponential on
numbers in that many of the standard identities for numbers carry
over to the types.
Corresponding to the law
(p ^ n) ^ m = p ^ (n * m)
we have the isomorphism
A → (B → C) ≃ (A × B) → C
Both types can be viewed as functions that given evidence that `A` holds
and evidence that `B` holds can return evidence that `C` holds.
This isomorphism sometimes goes by the name *currying*.
The proof of the right inverse requires extensionality.
\begin{code}
currying : ∀ {A B C : Set} → (A → B → C) ≃ (A × B → C)
currying =
record
{ to = λ{ f → λ{ (x , y) → f x y }}
; from = λ{ g → λ{ x → λ{ y → g (x , y) }}}
; from∘to = λ{ f → refl }
; to∘from = λ{ g → extensionality λ{ (x , y) → refl }}
}
\end{code}
Currying tells us that instead of a function that takes a pair of arguments,
we can have a function that takes the first argument and returns a function that
expects the second argument. Thus, for instance, our way of writing addition:
_+_ :
is isomorphic to a function that accepts a pair of arguments:
_+_ : ( × ) →
Agda is optimised for currying, so `2 + 3` abbreviates `_+_ 2 3`.
In a language optimised for pairing, we would take `2 + 3` as
an abbreviation for `_+_ (2 , 3)`.
Corresponding to the law
p ^ (n + m) = (p ^ n) * (p ^ m)
we have the isomorphism
(A ⊎ B) → C ≃ (A → C) × (B → C)
That is, the assertion that if either `A` holds or `B` holds then `C` holds
is the same as the assertion that if `A` holds then `C` holds and if
`B` holds then `C` holds. The proof of the left inverse requires extensionality.
\begin{code}
→-distrib-⊎ : ∀ {A B C : Set} → (A ⊎ B → C) ≃ ((A → C) × (B → C))
→-distrib-⊎ =
record
{ to = λ{ f → ( (λ{ x → f (inj₁ x) }) , (λ{ y → f (inj₂ y) }) ) }
; from = λ{ (g , h) → λ{ (inj₁ x) → g x ; (inj₂ y) → h y } }
; from∘to = λ{ f → extensionality λ{ (inj₁ x) → refl ; (inj₂ y) → refl } }
; to∘from = λ{ (g , h) → refl }
}
\end{code}
Corresponding to the law
(p * n) ^ m = (p ^ m) * (n ^ m)
we have the isomorphism
A → B × C ≃ (A → B) × (A → C)
That is, the assertion that if either `A` holds then `B` holds and `C` holds
is the same as the assertion that if `A` holds then `B` holds and if
`A` holds then `C` holds. The proof of left inverse requires both extensionality
and the rule `η-×` for products.
\begin{code}
→-distrib-× : ∀ {A B C : Set} → (A → B × C) ≃ (A → B) × (A → C)
→-distrib-× =
record
{ to = λ{ f → ( (λ{ x → proj₁ (f x) }) , (λ{ y → proj₂ (f y)}) ) }
; from = λ{ (g , h) → λ{ x → (g x , h x) } }
; from∘to = λ{ f → extensionality λ{ x → η-× (f x) } }
; to∘from = λ{ (g , h) → refl }
}
\end{code}
## Distribution
Products distributes over sum, up to isomorphism. The code to validate
this fact is similar in structure to our previous results.
\begin{code}
×-distrib-⊎ : ∀ {A B C : Set} → (A ⊎ B) × C ≃ (A × C) ⊎ (B × C)
×-distrib-⊎ =
record
{ to = λ{ ((inj₁ x) , z) → (inj₁ (x , z))
; ((inj₂ y) , z) → (inj₂ (y , z))
}
; from = λ{ (inj₁ (x , z)) → ((inj₁ x) , z)
; (inj₂ (y , z)) → ((inj₂ y) , z)
}
; from∘to = λ{ ((inj₁ x) , z) → refl
; ((inj₂ y) , z) → refl
}
; to∘from = λ{ (inj₁ (x , z)) → refl
; (inj₂ (y , z)) → refl
}
}
\end{code}
Sums do not distribute over products up to isomorphism, but it is an embedding.
\begin{code}
⊎-distrib-× : ∀ {A B C : Set} → (A × B) ⊎ C ≲ (A ⊎ C) × (B ⊎ C)
⊎-distrib-× =
record
{ to = λ{ (inj₁ (x , y)) → (inj₁ x , inj₁ y)
; (inj₂ z) → (inj₂ z , inj₂ z)
}
; from = λ{ (inj₁ x , inj₁ y) → (inj₁ (x , y))
; (inj₁ x , inj₂ z) → (inj₂ z)
; (inj₂ z , _ ) → (inj₂ z)
}
; from∘to = λ{ (inj₁ (x , y)) → refl
; (inj₂ z) → refl
}
}
\end{code}
Note that there is a choice in how we write the `from` function.
As given, it takes `(inj₂ z , inj₂ z)` to `(inj₂ z)`, but it is
easy to write a variant that instead returns `(inj₂ z)`. We have
an embedding rather than an isomorphism because the
`from` function must discard either `z` or `z` in this case.
In the usual approach to logic, both of the distribution laws
are given as equivalences, where each side implies the other:
A & (B C) ⇔ (A & B) (A & C)
A (B & C) ⇔ (A B) & (A C)
But when we consider the two laws in terms of evidence, where `_&_`
corresponds to `_×_` and `__` corresponds to `_⊎_`, then the first
gives rise to an isomorphism, while the second only gives rise to an
embedding, revealing a sense in which one of these laws is "more
true" than the other.
### Exercise (`×⊎-implies-⊎×`)
Show that a conjunct of disjuncts implies a disjunct of conjuncts.
\begin{code}
×⊎-Implies-⊎× = ∀ {A B C D : Set} → (A ⊎ B) × (C ⊎ D) → (A × C) ⊎ (B × D)
\end{code}
Does the converse hold? If so, prove; if not, explain why.
### Exercise (`⇔-refl`, `⇔-sym`, `⇔-trans`)
Define equivalence of propositions (also known as "if and only if") as follows.
\begin{code}
record _⇔_ (A B : Set) : Set where
field
to : A → B
from : B → A
\end{code}
Show that equivalence is reflexive, symmetric, and transitive.
### Exercise (`⇔-iso`)
Show that `A ⇔ B` is isomorphic to `(A → B) × (B → A)`.
## Standard library
Definitions similar to those in this chapter can be found in the standard library.
\begin{code}
import Data.Product using (_×_; _,_; proj₁; proj₂)
import Data.Unit using (; tt)
import Data.Sum using (_⊎_; inj₁; inj₂) renaming ([_,_] to ⊎-elim)
import Data.Empty using (⊥; ⊥-elim)
\end{code}
## Unicode
This chapter uses the following unicode.
× U+00D7 MULTIPLICATION SIGN (\x)
⊎ U+228E MULTISET UNION (\u+)
U+22A4 DOWN TACK (\top)
⊥ U+22A5 UP TACK (\bot)
η U+03B7 GREEK SMALL LETTER ETA (\eta)
₁ U+2081 SUBSCRIPT ONE (\_1)
₂ U+2082 SUBSCRIPT TWO (\_2)
⇔ U+21D4 LEFT RIGHT DOUBLE ARROW (\<=>)

View file

@ -1,394 +0,0 @@
---
title : "Quantifiers: Universals and Existentials"
layout : page
permalink : /Quantifiers
---
This chapter introduces universal and existential quantification.
## Imports
\begin{code}
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong)
open Eq.≡-Reasoning
open import Isomorphism using (_≃_; ≃-sym; ≃-trans; _≲_)
open Isomorphism.≃-Reasoning
open import Data.Nat using (; zero; suc; _+_; _*_)
open import Data.Nat.Properties.Simple using (+-suc)
open import Relation.Nullary using (¬_)
open import Function using (_∘_)
open import Data.Product using (_×_; _,_; proj₁; proj₂)
open import Data.Sum using (_⊎_; inj₁; inj₂)
\end{code}
We assume [extensionality][extensionality].
\begin{code}
postulate
extensionality : ∀ {A B : Set} {f g : A → B} → (∀ (x : A) → f x ≡ g x) → f ≡ g
\end{code}
[extensionality]: Equality/index.html#extensionality
## Universals
Given a variable `x` of type `A` and a proposition `B x` which
contains `x` as a free variable, the universally quantified
proposition `∀ (x : A) → B x` holds if for every term `M` of type
`A` the proposition `B M` holds. Here `B M` stands for
the proposition `B x` with each free occurrence of `x` replaced by
`M`. The variable `x` appears free in `B x` but bound in
`∀ (x : A) → B x`. We formalise universal quantification using the
dependent function type, which has appeared throughout this book.
Evidence that `∀ (x : A) → B x` holds is of the form
λ (x : A) → N
where `N` is a term of type `B x`, and `N x` and `B x` both contain
a free variable `x` of type `A`. Given a term `L` providing evidence
that `∀ (x : A) → B x` holds, and a term `M` of type `A`, the term `L
M` provides evidence that `B M` holds. In other words, evidence that
`∀ (x : A) → B x` holds is a function that converts a term `M` of type
`A` into evidence that `B M` holds.
Put another way, if we know that `∀ (x : A) → B x` holds and that `M`
is a term of type `A` then we may conclude that `B M` holds.
\begin{code}
∀-elim : ∀ {A : Set} {B : A → Set} → (∀ (x : A) → B x) → (M : A) → B M
∀-elim L M = L M
\end{code}
As with `→-elim`, the rule corresponds to function application.
Functions arise as a special case of dependent functions,
where the range does not depend on a variable drawn from the domain.
When a function is viewed as evidence of implication, both its
argument and result are viewed as evidence, whereas when a dependent
function is viewed as evidence of a universal, its argument is viewed
as an element of a data type and its result is viewed as evidence of
a proposition that depends on the argument. This difference is largely
a matter of interpretation, since in Agda values of a type and
evidence of a proposition are indistinguishable.
Dependent function types are sometimes referred to as dependent products,
because if `A` is a finite type with values `x₁ , ⋯ , xᵢ`, and if
each of the types `B x₁ , ⋯ , B xᵢ` has `m₁ , ⋯ , mᵢ` distinct members,
then `∀ (x : A) → B x` has `m₁ * ⋯ * mᵢ` members.
Indeed, sometimes the notation `∀ (x : A) → B x`
is replaced by a notation such as `Π[ x ∈ A ] (B x)`,
where `Π` stands for product. However, we will stick with the name
dependent function, because (as we will see) dependent product is ambiguous.
### Exercise (`∀-distrib-×`)
Show that universals distribute over conjunction.
\begin{code}
∀-Distrib-× = ∀ {A : Set} {B C : A → Set} →
(∀ (x : A) → B x × C x) ≃ (∀ (x : A) → B x) × (∀ (x : A) → C x)
\end{code}
Compare this with the result (`→-distrib-×`) in Chapter [Connectives](Connectives).
### Exercise (`⊎∀-implies-∀⊎`)
Show that a disjunction of universals implies a universal of disjunctions.
\begin{code}
⊎∀-Implies-∀⊎ = ∀ {A : Set} { B C : A → Set } →
(∀ (x : A) → B x) ⊎ (∀ (x : A) → C x) → ∀ (x : A) → B x ⊎ C x
\end{code}
Does the converse hold? If so, prove; if not, explain why.
## Existentials
Given a variable `x` of type `A` and a proposition `B x` which
contains `x` as a free variable, the existentially quantified
proposition `Σ[ x ∈ A ] B x` holds if for some term `M` of type
`A` the proposition `B M` holds. Here `B M` stands for
the proposition `B x` with each free occurrence of `x` replaced by
`M`. The variable `x` appears free in `B x` but bound in
`Σ[ x ∈ A ] B x`.
We formalise existential quantification by declaring a suitable
inductive type.
\begin{code}
data Σ (A : Set) (B : A → Set) : Set where
_,_ : (x : A) → B x → Σ A B
\end{code}
We define a convenient syntax for existentials as follows.
\begin{code}
infix 2 Σ-syntax
Σ-syntax = Σ
syntax Σ-syntax A (λ x → B) = Σ[ x ∈ A ] B
\end{code}
This is our first use of a syntax declaration, which specifies that
the term on the left may be written with the syntax on the right.
The special syntax is available only when the identifier
`Σ-syntax` is imported.
Evidence that `Σ[ x ∈ A ] B x` holds is of the form
`(M , N)` where `M` is a term of type `A`, and `N` is evidence
that `B M` holds.
Equivalently, we could also declare existentials as a record type.
\begin{code}
record Σ′ (A : Set) (B : A → Set) : Set where
field
proj₁ : A
proj₂ : B proj₁
\end{code}
Here record construction
record
{ proj₁ = M
; proj₂ = N
}
corresponds to the term
( M , N )
where `M` is a term of type `A` and `N` is a term of type `B M`.
Products arise a special case of existentials, where the second
component does not depend on a variable drawn from the first
component. When a product is viewed as evidence of a conjunction,
both of its components are viewed as evidence, whereas when it is
viewed as evidence of an existential, the first component is viewed as
an element of a datatype and the second component is viewed as
evidence of a proposition that depends on the first component. This
difference is largely a matter of interpretation, since in Agda values
of a type and evidence of a proposition are indistinguishable.
Existentials are sometimes referred to as dependent sums,
because if `A` is a finite type with values `x₁ , ⋯ , xᵢ`, and if
each of the types `B x₁ , ⋯ B xᵢ` has `m₁ , ⋯ , mᵢ` distinct members,
then `Σ[ x ∈ A] B x` has `m₁ + ⋯ + mᵢ` members, which explains the
choice of notation for existentials, since `Σ` stands for sum.
Existentials are sometimes referred to as dependent products, since
products arise as a special case. However, that choice of names is
doubly confusing, since universal also have a claim to the name dependent
product and since existential also have a claim to the name dependent sum.
A common notation for existentials is `∃` (analogous to `∀` for universals).
We follow the convention of the Agda standard library, and reserve this
notation for the case where the domain of the bound variable is left implicit.
\begin{code}
∃ : ∀ {A : Set} (B : A → Set) → Set
∃ {A} B = Σ A B
∃-syntax = ∃
syntax ∃-syntax (λ x → B) = ∃[ x ] B
\end{code}
The special syntax is available only when the identifier `∃-syntax` is imported.
We will tend to use this syntax, since it is shorter and more familiar.
Given evidence that `∀ x → B x → C` holds, where `C` does not contain
`x` as a free variable, and given evidence that `∃[ x ] B x` holds, we
may conclude that `C` holds.
\begin{code}
∃-elim : ∀ {A : Set} {B : A → Set} {C : Set} → (∀ x → B x → C) → ∃[ x ] B x → C
∃-elim f (x , y) = f x y
\end{code}
In other words, if we know for every `x` of type `A` that `B x`
implies `C`, and we know for some `x` of type `A` that `B x` holds,
then we may conclude that `C` holds. This is because we may
instantiate that proof that `∀ x → B x → C` to any value `x` of type
`A` and any `y` of type `B x`, and exactly such values are provided by
the evidence for `∃[ x ] B x`.
Indeed, the converse also holds, and the two together form an isomorphism.
\begin{code}
∀∃-currying : ∀ {A : Set} {B : A → Set} {C : Set} → (∀ x → B x → C) ≃ (∃[ x ] B x → C)
∀∃-currying =
record
{ to = λ{ f → λ{ (x , y) → f x y }}
; from = λ{ g → λ{ x → λ{ y → g (x , y) }}}
; from∘to = λ{ f → refl }
; to∘from = λ{ g → extensionality λ{ (x , y) → refl }}
}
\end{code}
The result can be viewed as a generalisation of currying. Indeed, the code to
establish the isomorphism is identical to what we wrote when discussing
[implication][implication].
[implication]: Connectives/index.html#implication
### Exercise (`∃-distrib-⊎`)
Show that universals distribute over conjunction.
\begin{code}
∃-Distrib-⊎ = ∀ {A : Set} {B C : A → Set} →
∃[ x ] (B x ⊎ C x) ≃ (∃[ x ] B x) ⊎ (∃[ x ] C x)
\end{code}
### Exercise (`∃×-implies-×∃`)
Show that an existential of conjunctions implies a conjunction of existentials.
\begin{code}
∃×-Implies-×∃ = ∀ {A : Set} { B C : A → Set } →
∃[ x ] (B x × C x) → (∃[ x ] B x) × (∃[ x ] C x)
\end{code}
Does the converse hold? If so, prove; if not, explain why.
## An existential example
Recall the definitions of `even` and `odd` from Chapter [Relations](Relations).
\begin{code}
data even : → Set
data odd : → Set
data even where
even-zero : even zero
even-suc : ∀ {n : } → odd n → even (suc n)
data odd where
odd-suc : ∀ {n : } → even n → odd (suc n)
\end{code}
A number is even if it is zero or the successor of an odd number, and
odd if it the successor of an even number.
We will show that a number is even if and only if it is twice some
other number, and odd if and only if it is one more than twice
some other number. In other words, we will show
even n iff ∃[ m ] ( m * 2 ≡ n)
odd n iff ∃[ m ] (1 + m * 2 ≡ n)
By convention, one tends to write constant factors first and to put
the constant term in a sum last. Here we've reversed each of those
conventions, because doing so eases the proof.
Here is the proof in the forward direction.
\begin{code}
even-∃ : ∀ {n : } → even n → ∃[ m ] ( m * 2 ≡ n)
odd-∃ : ∀ {n : } → odd n → ∃[ m ] (1 + m * 2 ≡ n)
even-∃ even-zero = zero , refl
even-∃ (even-suc o) with odd-∃ o
... | m , refl = suc m , refl
odd-∃ (odd-suc e) with even-∃ e
... | m , refl = m , refl
\end{code}
We define two mutually recursive functions. Given
evidence that `n` is even or odd, we return a
number `m` and evidence that `m * 2 ≡ n` or `1 + m * 2 ≡ n`.
We induct over the evidence that `n` is even or odd.
- If the number is even because it is zero, then we return a pair
consisting of zero and the (trivial) proof that twice zero is zero.
- If the number is even because it is one more than an odd number,
then we apply the induction hypothesis to give a number `m` and
evidence that `1 + m * 2 ≡ n`. We return a pair consisting of `suc m`
and evidence that `suc m * 2` ≡ suc n`, which is immediate after
substituting for `n`.
- If the number is odd because it is the successor of an even number,
then we apply the induction hypothesis to give a number `m` and
evidence that `m * 2 ≡ n`. We return a pair consisting of `suc m` and
evidence that `1 + 2 * m = suc n`, which is immediate after
substituting for `n`.
This completes the proof in the forward direction.
Here is the proof in the reverse direction.
\begin{code}
∃-even : ∀ {n : } → ∃[ m ] ( m * 2 ≡ n) → even n
∃-odd : ∀ {n : } → ∃[ m ] (1 + m * 2 ≡ n) → odd n
∃-even ( zero , refl) = even-zero
∃-even (suc m , refl) = even-suc (∃-odd (m , refl))
∃-odd ( m , refl) = odd-suc (∃-even (m , refl))
\end{code}
Given a number that is twice some other number we must show it is
even, and a number that is one more than twice some other number we
must show it is odd. We induct over the evidence of the existential,
and in the even case consider the two possibilities for the number
that is doubled.
- In the even case for `zero`, we must show `2 * zero` is even, which
follows by `even-zero`.
- In the even case for `suc n`, we must show `2 * suc m` is even. The
inductive hypothesis tells us that `1 + 2 * m` is odd, from which the
desired result follows by `even-suc`.
- In the odd case, we must show `1 + m * 2` is odd. The inductive
hypothesis tell us that `m * 2` is even, from which the desired result
follows by `odd-suc`.
This completes the proof in the backward direction.
### Exercise (`∃-even, ∃-odd`)
How do the proofs become more difficult if we replace `m * 2` and `1 + m * 2`
by `2 * m` and `2 * m + 1`? Rewrite the proofs of `∃-even` and `∃-odd` when
restated in this way.
## Existentials, Universals, and Negation
Negation of an existential is isomorphic to universal
of a negation. Considering that existentials are generalised
disjunction and universals are generalised conjunction, this
result is analogous to the one which tells us that negation
of a disjunction is isomorphic to a conjunction of negations.
\begin{code}
¬∃∀ : ∀ {A : Set} {B : A → Set} → (¬ ∃[ x ] B x) ≃ ∀ x → ¬ B x
¬∃∀ =
record
{ to = λ{ ¬∃xy x y → ¬∃xy (x , y) }
; from = λ{ ∀¬xy (x , y) → ∀¬xy x y }
; from∘to = λ{ ¬∃xy → extensionality λ{ (x , y) → refl } }
; to∘from = λ{ ∀¬xy → refl }
}
\end{code}
In the `to` direction, we are given a value `¬∃xy` of type
`¬ ∃[ x ] B x`, and need to show that given a value
`x` that `¬ B x` follows, in other words, from
a value `y` of type `B x` we can derive false. Combining
`x` and `y` gives us a value `(x , y)` of type `∃[ x ] B x`,
and applying `¬∃xy` to that yields a contradiction.
In the `from` direction, we are given a value `∀¬xy` of type
`∀ x → ¬ B x`, and need to show that from a value `(x , y)`
of type `∃[ x ] B x` we can derive false. Applying `∀¬xy`
to `x` gives a value of type `¬ B x`, and applying that to `y` yields
a contradiction.
The two inverse proofs are straightforward, where one direction
requires extensionality.
### Exercise (`∃¬-Implies-¬∀`)
Show `∃[ x ] ¬ B x → ¬ (∀ x → B x)`.
Does the converse hold? If so, prove; if not, explain why.
## Standard Prelude
Definitions similar to those in this chapter can be found in the standard library.
\begin{code}
import Data.Product using (Σ; _,_; ∃; Σ-syntax; ∃-syntax)
\end{code}
## Unicode
This chapter uses the following unicode.
∃ U+2203 THERE EXISTS (\ex, \exists)

31
src/extra/Nat.agda Normal file
View file

@ -0,0 +1,31 @@
module Nat where
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl)
open Eq.≡-Reasoning using (begin_; _≡⟨⟩_; _∎)
data : Set where
zero :
suc :
{-# BUILTIN NATURAL #-}
_+_ :
zero + n = n
(suc m) + n = suc (m + n)
_ : 2 + 3 5
_ =
begin
2 + 3
≡⟨⟩
suc (1 + 3)
≡⟨⟩
suc (suc (0 + 3))
≡⟨⟩
suc (suc 3)
≡⟨⟩
5