-- With the following three lines of code, a new datatype is created.
-- Its name is "Bool" and its values are "false" and "true".
data Bool : Set₀ where
  false : Bool
  true  : Bool

-- https://agdapad.quasicoherent.io/#Padova2025/viewonly

data  : Set where   -- \bN
  zero : 
  succ :       -- "successor"
-- The inhabitants of ℕ are:
-- zero, succ zero, succ (succ zero), succ (succ (succ zero)), ...

-- For instance, "double two" should be "four".
double :   
double zero     = zero
double (succ x) = succ (succ (double x))
-- informally, in blackboard mathematics:
-- double(succ(x)) = 2*(1+x) = 2+2x = 1+(1+2x) = succ(succ(2x)) = succ(succ(double(x)))

add :     
add zero     y = y
add (succ x) y = succ (add x y)
-- informally, in blackboard mathematics:
-- succ(x)+y = (1+x)+y = 1+(x+y) = succ(x+y)

_+_ :     
zero   + y = y
succ x + y = succ (x + y)

-- in blackboard mathematics, 3! = 3 * 2 * 1

_! :   
x ! = {!!}

data Weird : Set where
  foo : Weird  Weird
-- What are values of type Weird?
-- There are no values of type Weird.
-- This type is empty.

-- If we write "f x y", then Agda interprets this as the blackboard-mathematics "f(x,y)",
-- so as calling "f" with two arguments.

one : 
one = succ zero

two : 
two = succ (succ zero)

-- In C, bool isTheSunShining;
is-the-sun-shining : Bool
is-the-sun-shining = true

-- The identity function.
--
-- def id(x):
--   return x
--
-- bool id(bool x) {
--   return x;
-- }
id : Bool  Bool   -- \to \alpha α
id x = x

-- The negation function.
--
-- def neg(x):
--   if x:
--     return False
--   else:
--     return True
--
-- bool neg(bool x) {
--   if(x) {
--     return false;
--   } else {
--     return true;
--   }
-- }

neg : Bool  Bool
neg false = true
neg true  = false
-- This is a definition "by pattern matching".

-- We make a hole appear by writing a "?" and then pressing C-c C-l.

-- C-c C-l: load file
-- C-c C-v: evaluate term
-- C-c C-c: case split  (if the cursor is in a hole)
-- C-c C-space: check hole
-- C-c C-a: automatic mode

-- In blackboard mathematics: f(x), sin(π)
-- In Agda:                   f x,  sin π, id x

-- Set is the type of small types. In MLTT, "Set" is called "U₀".
-- Set itself is not a small type, but a large type.
-- The type of all large types is Set₁.
-- Set₁ itself it not a large type, but a very large type.
-- The type of all very large types is Set₂.
--
-- "Set" and "Set₀" are synonymous.
--
-- false : Bool : Set : Set₁ : Set₂ : Set₃ : Set₄ : ... : Setω : Setω+1 : ... : Setω2
--
-- The naive idea of a "set of all sets" or a "type of all types"
-- is inconsistent. In set theory, this is known as Russell's paradox,
-- and in type theory, this is known as Girard's paradox.

-- In Agda, by default, we do not have the "powerset axiom".
-- This axiom states that every set has a powerset.

fun :   (  )
fun zero        = id'
  where
  id' :   
  id' x = x
fun (succ zero) = double
fun _           = succ



{-
  * dependent types
  * lists, vectors
  * implicit parameters
-}

-- Most programming languages only support non-dependent types:
-- int, float, double, string, int[], ...

-- In contrast, Agda also supports dependent types -- these
-- are types which depend on values:
-- Vector ℕ a, the type of length-a-lists of natural numbers

Foo :   Set
Foo zero               = Bool
Foo (succ zero)        = 
Foo (succ (succ zero)) = Bool  Bool
Foo _                  = 


Bar :   Set₁
Bar zero = Bool'
  where
  data Bool' : Set₁ where
    false : Bool'
    true  : Bool'
  favorite-number : 
  favorite-number = succ (succ (succ zero))
Bar _    = Set


-- Let's define the type of lists of natural numbers.
-- So this type should contain, for instance, the list (two ∷ (four ∷ (zero ∷ (one ∷ [])))).
data NatList : Set where
  []  : NatList
  _∷_ :   NatList  NatList
  -- The constructor "_∷_" takes two arguments,
  -- namely a natural number and
  -- an already-constructed list.

-- The following three lines of code introduce, for each X : Set, a type List X.
data List (X : Set) : Set where
  []  : List X
  _∷_ : X  List X  List X
  -- "X" is a "parameter" of this definition

newExampleList : List Bool
newExampleList = true  (true  (false  (true  [])))

-- double' : (a : ℕ) → ℕ........here we could use a.......
-- double' zero = zero
-- double' (succ x) = succ (succ (double' x))

-- "newLength" is a function which inputs two arguments, namely
-- - a type X
-- - a list xs : List X
-- and outputs the length of the list xs.
newLength : (X : Set)  List X  
newLength X []       = zero
newLength X (x  xs) = succ (newLength X xs)

-- With the curly braces {...}, we mark the argument as implicit, so
-- that we do not need to explicitly supply it when calling the newLength' function.
newLength' : {X : Set}  List X  
newLength' []       = zero
newLength' (x  xs) = succ (newLength' xs)

example-usage : 
example-usage = newLength' {Bool} newExampleList

idBool : Bool  Bool
idBool x = x

idNat :   
idNat x = x

idListBool : List Bool  List Bool
idListBool x = x

-- In type theory, we would write:
--   generalIdentityFunction : Π_(X : Set) Π_(u : X) X
-- This function is a function which inputs two arguments, namely
-- - a type X (implicit) and
-- - a value u of type X.
generalIdentityFunction : {X : Set}  X  X
generalIdentityFunction u = u

-- By the type signature, the function "choice" would need to do the following:
-- Read a type X as input; produce a value of type X as output.
choice : (X : Set)  X
choice X = {!!}
-- this hole can never be filled, because of the case that X is empty

postulate
  crazy-number : 
  foo-function : Bool  
  -- axiom-of-choice : (X : InhabitedSet) → X

data ListOfBooleans : Set where
  []  : ListOfBooleans
  _∷_ : Bool  ListOfBooleans  ListOfBooleans

exampleList : NatList
exampleList = two  (one  [])

length : NatList  
length []       = zero
length (x  xs) = succ (length xs)
-- For instance, length exampleList should be two.


ex : Foo zero
ex = false
-- in Agdapad:         C-c C-,
-- in Let's play Agda: C-c ,

ex₂ : Foo one
ex₂ = two

-- The type "Foo n" depends on the value n.