{-
Today (?):
1. A riddle in termination
2. Disjunction (∨), existential quantification (∃), conjunction (∧)
3. Assisting you with exercises :-)
-}
open import Padova2025.ProgrammingBasics.Naturals.Base
open import Padova2025.ProgrammingBasics.Naturals.Arithmetic
open import Padova2025.ProvingBasics.Equality.Base
{-
f : ℕ → ℕ
f zero = zero
f (succ x) = f (f x)
-- Agda complains: "Termination checking failed".
-}
{-
Motto: Agda is like a calculator, but for logic.
(Nothing more, nothing less.)
Agda is very careful, very diligent, but not smart.
-}
-- f one = f (succ zero) = f (f zero) = f zero = zero
-- f two = f (succ one) = f (f one) = f zero = zero
-- f three = ... = zero
-- ...
{-
Five ways of dealing with that issue:
0. Give up, do something else
1. Promise to Agda that the recursion terminates
2. Mark the function as non-terminating, so that we can continue,
but the function will never be unrolled during type checking
3. Use a brittle kind of gas
4. Use a more sophisticated kind of gas
5. Prove termination
-}
-- Option 1 (rejected by Agda if {-# OPTIONS --safe #-} is active)
{-# TERMINATING #-}
f : ℕ → ℕ
f zero = zero
f (succ x) = f (f x)
-- Option 2 (rejected by Agda if {-# OPTIONS --safe #-} is active)
{-# NON_TERMINATING #-}
g : ℕ → ℕ
g zero = zero
g (succ x) = g (g x)
g-eq : (x : ℕ) → g (succ x) ≡ g (g x)
g-eq x = {!refl!}
{-# NON_TERMINATING #-}
loop : zero ≡ one
loop = loop
-- In blackboard mathematics, this proof attempt would like this:
-- Result A. 0 = 1.
-- Proof. This follows from Result A. ∎
-- Option 3.
h : ℕ → ℕ
h x = go (succ x) x
where
go : ℕ → ℕ → ℕ
go zero x = four -- fantasy value, hopefully never reached
go (succ gas) zero = zero
go (succ gas) (succ x) = go gas (go gas x)
-- Option 5.
-- Let us introduce a type "Def x" containing witnesses that
-- the funtion is defined on input "x", i.e. that the recursion terminates
-- on input "x".
{-
fun zero = zero
fun (succ x) = fun (fun x)
-}
data Def : ℕ → Set
fun : (x : ℕ) → Def x → ℕ
data Def where
base : Def zero
-- "fun terminates on input zero."
step : {x : ℕ} → (p : Def x) → Def (fun x p) → Def (succ x)
-- "If 'fun x' terminates and if 'fun (fun x)' terminates, then also
-- 'fun (succ x)' terminates."
-- "If fun is defined on input x and if fun is defined on input (fun x);
-- then fun is also defined on input succ x."
fun zero base = zero
fun (succ x) (step p q) = fun (fun x p) q
fun-is-defined-on-input-one : Def one
fun-is-defined-on-input-one = step base base
fun-is-defined-on-input-two : Def two
fun-is-defined-on-input-two = step fun-is-defined-on-input-one base
-- Logical reading: For every number x, the function is defined on input x.
-- Computational reading: "theorem" inputs a number x and outputs a witness
-- that the function is defined on input x.
theorem : (x : ℕ) → Def x
theorem x = {!!}
open import Padova2025.ProvingBasics.EvenOdd
open import Padova2025.ProvingBasics.Negation
-- "A ⊎ B" is the disjoint union of the types "A" and "B".
data _⊎_ (A B : Set) : Set where
left : A → A ⊎ B -- Logical reading: If A, then A or B.
right : B → A ⊎ B -- Logical reading: If B, then A or B.
-- The inhabitants of A ⊎ B are:
-- For each x : A, we have "left x" as an inhabitant of A ⊎ B.
-- For each y : B, we have "right y" as an inhabitant of A ⊎ B.
one-is-even-or-odd : Even one ⊎ Odd one
one-is-even-or-odd = right base-odd
five-is-even-or-odd : Even five ⊎ Odd five
five-is-even-or-odd = right (step-odd (step-odd base-odd))
every-number-is-zero-or-not-zero : (x : ℕ) → (x ≡ zero) ⊎ (¬ (x ≡ zero))
every-number-is-zero-or-not-zero x = {!!}
oracle : {A : Set} → ¬ ¬ (A ⊎ (¬ A))
oracle = λ k → k (right (λ x → k (left x)))
-- "Every number is either even or odd."
-- "Even x ⊎ Odd x" is the type of witnesses that x is even or that x is odd.
even-or-odd : (x : ℕ) → Even x ⊎ Odd x
even-or-odd zero = left base-even
even-or-odd (succ zero) = right base-odd
even-or-odd (succ (succ x)) with even-or-odd x
... | left p = left (step-even p)
... | right q = right (step-odd q)
even-or-odd' : (x : ℕ) → Even x ⊎ Odd x
even-or-odd' zero = left base-even
even-or-odd' (succ zero) = right base-odd
even-or-odd' (succ (succ x)) = lemma (even-or-odd' x)
where
lemma : {a : ℕ} → Even a ⊎ Odd a → Even (succ (succ a)) ⊎ Odd (succ (succ a))
lemma (left p) = left (step-even p)
lemma (right q) = right (step-odd q)
{-
{ left (step-even p), if even-or-odd x is of the form left p
even-or-odd (succ (succ x)) = {
{ right (step-odd q), if even-or-odd x is of the form right q
-}
example : ℕ → ℕ
example x with even-or-odd x
... | left p = four + x
... | right q = three
_ : example five ≡ three
_ = refl
_ : example four ≡ four + four
_ = refl
_ : example four ≡ succ (succ (succ (succ (succ (succ (succ (succ zero)))))))
_ = refl
-- "Beyond every natural number, there is an even number."
-- ∀(x ∈ ℕ). ∃(y ∈ ℕ). (y ≥ x ∧ Even(y))
-- Given a type A and given a predicate P : A → Set (for instance A = ℕ, P = Even),
-- there is a type "Σ A P" of witnesses that there is at least one x : A such that P x holds.
-- These witnesses are dependent pairs (x , p) consisting of a suitable value x : A and a witness p : P x.
-- A nicer syntax for writing this type is: "Σ[ x ∈ A ] P x"
-- In case we do not want to specify the type A, an abbreviation is: "∃[ x ] P x"
data Σ (A : Set) (P : A → Set) : Set where
⟦_,_⟩ : (x : A) → P x → Σ A P
there-exists-at-least-one-odd-number : Σ ℕ Odd
there-exists-at-least-one-odd-number = ⟦ one , base-odd ⟩
there-exists-at-least-one-odd-number' : Σ ℕ Odd
there-exists-at-least-one-odd-number' = ⟦ three , step-odd base-odd ⟩
beyond-every-natural-number-there-is-an-even-number : (x : ℕ) → Σ ℕ (λ y → {!......... Even y!})
-- beyond-every-natural-number-there-is-an-even-number : (x : ℕ) → ∃[ y ] ...... Even y
beyond-every-natural-number-there-is-an-even-number x = {!!}
-- A witness for a conjunction "A and B" should consist of a witness for A and a witness for B,
-- i.e. a witness for "A and B" should be a pair consisting of a witness for A and a witness for B.
data _×_ (A B : Set) : Set where
_,_ : A → B → A × B
-- In other words, "A × B" is the type of pairs of elements of A and elements of B.
-- "Cartesian product type".
-- Its inhabitants are of the form (x , y) with x : A and y : B.
four-is-even-and-five-is-odd : Even four × Odd five
four-is-even-and-five-is-odd = step-even (step-even base-even) , step-odd (step-odd base-odd)