Let's play Agda
{-# OPTIONS --cubical-compatible #-}
module Padova2025.ProvingBasics.Equality.Booleans where

Results on Booleans#

open import Padova2025.ProgrammingBasics.Booleans
open import Padova2025.ProgrammingBasics.Operators
open import Padova2025.ProvingBasics.Negation
open import Padova2025.ProvingBasics.Equality.Base
open import Padova2025.ProvingBasics.Equality.General

Exercise: False is not true#

Exercise 1false≢true
false≢true : false ≢ true
false≢true = {!!}
Reference solution
false≢true : false ≢ true
false≢true ()

Exercise: Double negation#

Exercise 2not²
not² : (x : Bool) → not (not x) ≡ x
not² = {!!}
The reference solution uses: false refl true
Reference solution
not² : (x : Bool) → not (not x) ≡ x
not² false = refl
not² true  = refl

Exercise: Commutativity of logical AND#

Exercise 3&&-comm
&&-comm : (x y : Bool) → (x && y) ≡ (y && x)
&&-comm = {!!}
The reference solution uses: false refl true
Reference solution
&&-comm : (x y : Bool) → (x && y) ≡ (y && x)
&&-comm false false = refl
&&-comm false true  = refl
&&-comm true  false = refl
&&-comm true  true  = refl

Tautologies#

Before we have discussed a function is-tautology₁ : (Bool → Bool) → Bool with the purpose of returning true if and only if the first argument is constantly true. A straightforward implementation is the following:

is-tautology₁ : (Bool → Bool) → Bool
is-tautology₁ f = f false && f true

However, a more cryptic implementation is also possible.

is-tautology₁' : (Bool → Bool) → Bool
is-tautology₁' f = f (f false)

Let us verify that this alternatively works correctly. To this end, we first formalize what it means for a function to be constantly true:

ConstantlyTrue : (Bool → Bool) → Set
ConstantlyTrue f = (x : Bool) → f x ≡ true

In other words, an element of the type ConstantlyTrue f is a function which maps every input x : Bool to a witness that f x ≡ true. We are then ready to state and prove that is-tautology₁' f correctly returns true if f is constantly true:

Exercise 4part₁
part₁ : (f : Bool → Bool) → ConstantlyTrue f → is-tautology₁' f ≡ true
part₁ = {!!}
The reference solution uses: false
Reference solution
part₁ : (f : Bool → Bool) → ConstantlyTrue f → is-tautology₁' f ≡ true
part₁ f p = p (f false)

The converse direction is more involved. One way to structure the argument is to first verify an auxiliary lemma.

Exercise 5γ
γ : (f : Bool → Bool) → (a : Bool) → f false ≡ a → f a ≡ true → ConstantlyTrue f
γ = {!!}
The reference solution uses: trans sym
Reference solution
γ : (f : Bool → Bool) → (a : Bool) → f false ≡ a → f a ≡ true → ConstantlyTrue f
γ f false p q false = q
γ f false p q true  with trans (sym p) q
... | ()
γ f true  p q false = p
γ f true  p q true  = q
Exercise 6part₂
part₂ : (f : Bool → Bool) → is-tautology₁' f ≡ true → ConstantlyTrue f
part₂ f = {!!}
The reference solution uses: γ false refl
Reference solution
part₂ : (f : Bool → Bool) → is-tautology₁' f ≡ true → ConstantlyTrue f
part₂ f = γ f (f false) refl

This way of structuring the argument is due to Martín Escardó, who has explored this topic in great detail.