-- AGDA IN PADOVA 2022
-- Exercise sheet 1


--------------------
----[ BOOLEANS ]----
--------------------

data Bool : Set where
  false : Bool
  true  : Bool

_&&_ : Bool  Bool  Bool
false && b     = false
true  && false = false
true  && true  = true

-- EXERCISE: Implement boolean "or".
-- "false || true" should evaluate to "true".
-- "true  || true" should evaluate to "true".
_||_ : Bool  Bool  Bool
false || b = b
true  || b = true

_||'_ : Bool  Bool  Bool
false ||' false = false
false ||' true  = true
true  ||' b     = true

-- EXERCISE: Implement a function "is-tautology₁?" which checks whether
-- a given input function is constantly true. For instance, if f x = x,
-- then "is-tautology₁ f" should evaluate to "false".
constantly-true : Bool  Bool
constantly-true x = true

constantly-true' : Bool  Bool
constantly-true' false = true
constantly-true' true  = true

is-tautology₁ : (Bool  Bool)  Bool
is-tautology₁ f = f false && f true
-- does not work: is-tautology₁ f = f ≡ constantly-true
-- in math: is-tautology₁(f) = f(false) && f(true)

-- EXERCISE: Implement a function "is-tautology₂?" which checks whether
-- a given input function of two arguments is constantly true. For
-- instance, if f x y = true, then "is-tautology₂ f" should evaluate to "true".
is-tautology₂ : (Bool  Bool  Bool)  Bool
is-tautology₂ f = {!!}

-- COMMENT:
-- Function extensionality means: "If f x = g x for all x, then f = g."

---------------------------
----[ NATURAL NUMBERS ]----
---------------------------

data  : Set where
  zero : 
  succ :   

_+_ :     
zero   + b = b
succ a + b = succ (a + b)

-- EXERCISE: Define the function "half" which divides its input by two.
-- For instance "half (succ (succ (succ (succ zero))))" should be "succ (succ zero)"
-- and "half (succ (succ (succ zero)))" should be "succ zero" (so we round down).
half :   
half zero            = zero
half (succ zero)     = zero   -- in math: half(1) = 0.5 = 0 (rounded down)
half (succ (succ n)) = succ (half n)
-- (1+n)/2 = 0.5 + n/2
-- (1+1+n)/2 = 1 + n/2

-- EXERCISE: Define (cut-off) subtraction. For instance "succ zero - succ zero"
-- and "succ zero - succ (succ zero)" should both be "zero".
_-_ :     
a - b = {!!}

-- EXERCISE: Define multiplication and exponentiation.

-- EXERCISE: Define a function "eq?" which determines whether its two
-- input numbers are equal. For instance, "eq? zero zero" should evaluate
-- to "true" while "eq? zero (succ zero)" should evaluate to "false".
eq? :     Bool
eq? a b = {!!}

-- EXERCISE: Define a function "≤?" which determines whether its first
-- argument is less than or equal to its second. For instance, "≤?
-- zero zero" should evaluate to "true" while "≤? (succ zero) zero"
-- should evaluate to "false".
≤? :     Bool
≤? a b = {!!}

-- EXERCISE: Define a function "even?" which determines whether its input is even.
-- For instance, "even? zero" and "even? (succ (succ zero))" should both evaluate to "true",
-- while "even? (succ zero)" should evaluate to "false".
even? :   Bool
even? zero            = true
even? (succ zero)     = false
even? (succ (succ n)) = even? n

¬_ : Bool  Bool
¬ false = true
¬ true  = false

even?' :   Bool
even?' zero     = true
even?' (succ n) = ¬ (even?' n)

-- EXERCISE: Describe the following type in simple terms. What are its values?
data Weird : Set where
  foo : Weird  Weird
-- There are no values of the type Weird!

data  : Set where  -- \emptyset
-- this is the manifestly empty type.

empty-function :   
empty-function ()

question :   
question n = {!!}  -- this hole is unfillable

prior-question :   
prior-question x = x

prior-question' :   
prior-question' ()

bonus-question : Weird  
bonus-question (foo x) = bonus-question x


-- on to dependent types!

-- The type "list of integers" depends on the type of integers, but
-- this is still a type (and not a value), and hence the type "list of integers"
-- would not usually be called a "dependent type".

-- The type "vectors of length n" depends on the number n (which is a value, not a type),
-- and hence the type "vectors of length n" would be called a "dependent type".

data Vector :   Set where
  []  : Vector zero
  _∷_ : {n : }  Bool  Vector n  Vector (succ n)

example-vector : Vector (succ (succ (succ zero)))
example-vector = false  (true  (true  []))  -- [false,true,true]

false-vector : {n : }  Vector n
false-vector {zero}   = []
false-vector {succ n} = false  false-vector

ex : Vector (succ (succ (succ zero)))
ex = false-vector

-- "false-vector (succ (succ (succ zero)))" should evaluate to "false ∷ (false ∷ (false ∷ [])))"

data Vector' (A : Set) :   Set where
  []  : Vector' A zero
  _∷_ : {n : }  A  Vector' A n  Vector' A (succ n)
-- for instance, Vector' Bool (succ (succ zero)) is the type of boolean vectors of length 2.
-- for instance, Vector' ℕ    (succ (succ zero)) is the type of vectors of length 2 whose entries are natural numbers.

data Vector'' : Set    Set where
  []  : {A : Set}  Vector'' A zero
  _∷_ : {A : Set} {n : }  A  Vector'' A n  Vector'' A (succ n)
  -- ♥   : Vector'' Bool (succ (succ zero))

-- for instance, "map f (x ∷ (y ∷ (z ∷ [])))" should evaluate to "f x ∷ (f y ∷ (f z ∷ []))".
-- map : {A : Set} → {B : Set} → {n : ℕ} → (A → B) → Vector' A n → Vector' B n
map : {A B : Set} {n : }  (A  B)  Vector' A n  Vector' B n
map f []       = []
map f (x  xs) = f x  map f xs

-- Set is the type of all small types; it's the "universe".
-- for instance, ℕ : Set
-- for instance, Bool : Set
-- for instance, ∅ : Set

-- zero : ℕ : Set : Set₁ : Set₂ : Set₃ : Set₄ : ...

-- Agda has a mode to switch it as follows: zero : ℕ : Set : Set : Set : Set : Set : ...
-- The resulting system will be inconsistent (be able to prove 1 = 0).

-- ℕ is actually a value of type Set. :-)