-- Whirlwind tour to forcing :-)
-- (Invented by Paul Cohen in 1963, got the Fields Medal.)

{-
  In algebra and analysis, we are accustomed to extending
  mathematical structures:
  -- ℚ has holes, hence pass to ℝ.
     Every real number is a limit of better and better approximations
     by rational numbers: 3, 3.1, 3.14, ...
  -- ℝ doesn't contain a square root of -1, hence pass to ℂ
     (note: ℝ ∪ { i } is also a nice set, but not a field)
  -- From ℂ, pass to ℂ[X] which contains the new "generic number" X
  -- ...

  In set theory, we extend the base mathematical universe.
  The extended universes are called forcing extensions of the
  base universe.
  -- There is a forcing extension containing a new function ℕ → ℕ,
     the so-called "generic function ℕ → ℕ".
  -- There is a forcing extension containing a new set X.
  -- There is a forcing extension containing a new maximal ideal
     for a given commutative ring.
  -- There is a forcing extension containing a new surjection ℕ → X,
     the so-called "generic surjection ℕ → X". This construction
     works and is nontrivial and has applications for any inhabited set X
     of the base universe (including uncountable sets).
-}

module _ (X : Set) (x₀ : X) where
-- "Let a set X be given. Let an element x₀ be given."

-- What should an approximation to a surjection ℕ → X be?
-- Answer: Finite lists of elements of X.
-- For instance the finite list a ∷ b ∷ c ∷ [] can be regarded
-- as the following partially-defined partially-surjective function f : ℕ → X:
-- f zero = a
-- f one  = b
-- f two  = c

-- Over time, approximations may evolve to better approximations.

-- Let "f₀ : ℕ → X" be our name for the generic surjection living in
-- the forcing extension. Unfortunately, Agda does not support a "forcing mode"
-- by which we could switch to the forcing extension. In the forcing extension,
-- f₀ would be an actual function, and given n : ℕ and an element x : X,
-- the assertion "f₀ n ≡ x" would be an ordinary assertion.

-- Instead, we need to use the language of the base universe to talk about
-- the forcing extension.

open import Padova2025.ProgrammingBasics.Lists
open import Padova2025.ProgrammingBasics.Naturals.Base

L : Set
L = List X
-- the type of approximations

-- Let us now define "f₀ n ≡ x". We will write this as "f₀[ n ]≡ x".
f₀[_]≡_ :   X  (L  Set)
f₀[ n ]≡ x = λ xs  {!...the n'th element in the list xs is equal to x....!}

-- Given an approximation-depending proposition P : L → Set,
-- ∇ P xs will express the following: "No matter how xs evolves over time to
-- a better approximation ys, eventually P ys will hold."
data  (P : L  Set) : L  Set where
  now    : {xs : L}  P xs   P xs
  later₁ : {xs : L}  ((x : X)   P (xs ∷ʳ x))   P xs
  later₂ : {xs : L}  (y : X)
     ((ys : L)  {!...y occurs somewhere in xs ++ ys.....!}   P (xs ++ ys))   P xs