module Dickson where

{-
  Extracting constructive content from classical proofs
  https://agdapad.quasicoherent.io/~cirm2025/Dickson.agda

  Plan:
  0. Entertaining a ludicrous classical proof in English
  1. Formalizing the classical proof
  2. Turning the classical proof into a constructive but
     uninformative proof
  3. Fully constructivizing the proof

  Theorem (mini version of Dickson's lemma):
  For every function f : ℕ → ℕ, there is a number n : ℕ
  such that f(n) ≤ f(n+1).

  Proof (classical). By the law of excluded middle,
  there is a minimum value f(n). Hence, in particular,
  we will have f(n) ≤ f(n+1).

  Beautiful constructive proofs can be found in
  Iosif Petrakis: Constructive Combinatorics of Dickson's Lemma.
  But can we interpret the given classical proof as a blueprint for a
  constructive proof?
-}

open import Data.Nat
open import Data.Sum
open import Data.Product

module Classical where
  open import Data.Empty
  open import Relation.Nullary
  
  postulate
    -- Logical reading: For any A, either A or not A.
    -- Computational reading: "oracle" is a function
    -- which reads a set A as input and outputs
    -- either an element of A or a witness that A is empty.
    oracle : (A : Set)  A  (A  )

        -- ∀(f : ℕ → ℕ).  ∃n:ℕ. ∀(m : ℕ). f(n) ≤ f(m)
  {-# TERMINATING #-}
  minimum : (f :   )  ∃[ n ] ((m : )  f n  f m)
  minimum f = go 0
    where
    go :   ∃[ n ] ((m : )  f n  f m)
    go i with oracle (∃[ j ] f j < f i)
    ... | inj₁ (j , fj<fi) = go j
    ... | inj₂ p           = (i , h)
      where
      h : (m : )  f i  f m
      h m with ≤-<-connex (f i) (f m)
      ... | inj₁ fi≤fm = fi≤fm
      ... | inj₂ fi>fm = ⊥-elim (p (m , fi>fm))

  --       ∀(f : ℕ → ℕ).  ∃n:ℕ.  f(n) ≤ f(n+1)
  theorem : (f :   )  ∃[ n ] f n  f (n + 1)
  theorem f with minimum f
  ... | (n , p) = (n , p (n + 1))
  -- Here, p is a witness that f n is the minimum of f:
  -- Logical reading: p is a witness of ∀(m : ℕ). f(n) ≤ f(m).
  -- Computational reading: p is a function which reads as input
  -- a number m : ℕ and which outputs a witness that f(n) ≤ f(m).

example :   
example 0 = 17
example 1 = 15
example 2 = 14
example _ = 47

module ConstructiveButUninformative ( : Set) where
  ¬_ : Set  Set
  ¬ X = (X  )

  escape : ¬ ¬   
  escape x = x  z  z)

  ⊥-elim : {A : Set}    ¬ ¬ A
  ⊥-elim x = λ z  x

  oracle : (A : Set)  ¬ ¬ (A  (A  ))
  oracle A = λ z  z (inj₂  z₁  z (inj₁ z₁)))

  return : {A : Set}  A  ¬ ¬ A
  return x = λ z  z x

  -- If ¬¬A, and if A → B, then also ¬¬B.
  -- If ¬¬A, and if A → ¬¬B, then also ¬¬B.
  _>>=_ : {A B : Set}  ¬ ¬ A  (A  ¬ ¬ B)  ¬ ¬ B
  m >>= f = λ z  m  z₁  f z₁ z)

  {-# TERMINATING #-}
  minimum : (f :   )  ¬ ¬ (∃[ n ] ((m : )  ¬ ¬ (f n  f m)))
  minimum f = go 0
    where
    go :   ¬ ¬ (∃[ n ] ((m : )  ¬ ¬ (f n  f m)))
    go i = oracle (∃[ j ] f j < f i) >>= g
      where
      g : _  _
      g (inj₁ (j , fj<fi)) = go j
      g (inj₂ p)           = return (i , h)
        where
        h : (m : )  ¬ ¬ (f i  f m)
        h m with ≤-<-connex (f i) (f m)
        ... | inj₁ fi≤fm = return fi≤fm
        ... | inj₂ fi>fm = ⊥-elim (p (m , fi>fm))

  theorem : (f :   )  ¬ ¬ (∃[ n ] f n  f (n + 1))
  theorem f = do
    (n , p)  minimum f
    fn≤fn+1  p (n + 1)
    return (n , fn≤fn+1)

module Constructive (f :   ) where
  Claim : Set
  Claim = ∃[ n ] f n  f (n + 1)

  thm : Claim
  thm = escape (theorem f)
    where
    open ConstructiveButUninformative Claim
    -- "Now use all the results of the previous section,
    -- but with Claim in place of ⊥."

-- Barr's theorem:
-- Friedman's trick works for Π² statements, so statements
-- of the form ∀x ∃y ...

-- ZFC is conservative over IZF for arithmetical Π² statements.
-- By applying the L-translation, ZFC is conservative over ZF
-- for arithmetical statements.
-- By applying the ¬¬-translation followed by Friedman's trick,
-- ZF is conservative over IZF for Π² statements.

-- nontrivial exit continuation trick