{-# OPTIONS --without-K --safe #-}

module lecture1 where
import introduction

Type = Set
Type₁ = Set₁

data Bool : Type where
 true false : Bool

-- Type "→" as "\to" or "\->"
not : Bool  Bool
not true  = false
not false = true

idBool : Bool  Bool
idBool x = x

idBool' : Bool  Bool
idBool' = λ (x : Bool)  x

-- The following is a Π type
id' : (X : Type)  X  X
id' X x = x

-- Implicit
id : {X : Type}  X  X
id x = x

idBool'' : Bool  Bool
idBool'' = id' _

-- "propositions as types" "mathematical statements as types"
example : {P Q : Type}  P  (Q  P)
example {P} {Q} p = f
 where
  f : Q  P
  f _ = p

example' : {P Q : Type}  P  (Q  P)
example' p = λ q  p

open import binary-products

-- "×" is "and" in propositions as types
ex : {P Q : Type}  P × Q  Q × P
ex (p , q) = (q , p)

-- \bN
data  : Type where
 zero : 
 suc  :   

three : 
three = suc (suc (suc zero))

-- {-# BUILTIN NATURAL ℕ #-}
-- for technical reasons we can not have this binding here. however
-- there is already a type ℕ in the introduction module which /does/
-- support numeral notation. we are careful not to use the ℕ type
-- defined in this module again.

three' : introduction.ℕ
three' = 3 -- synonym for the above

D : Bool  Type
D true  = introduction.ℕ
D false = Bool

-- "mix-fix" operator (3rd sense of "_" in Agda)
--                           b      x   y
if_then_else_ : {X : Type}  Bool  X  X  X
if true  then x else y = x
if false then x else y = y

if[_]_then_else_ : (X : Bool  Type)
                  (b : Bool)
                  X true
                  X false
                  X b
if[ X ] true then  x else y = x
if[ X ] false then x else y = y

-- Π (b : Bool), D b
unfamiliar : (b : Bool)  D b
unfamiliar b = if[ D ] b then 3 else false

data List (A : Type) : Type where
 []   : List A  -- empty list
 _::_ : A  List A  List A -- if xs is a list then x :: xs is list

infixr 10 _::_

ff : Type  Type
ff = List

sample-list₀ : List introduction.ℕ
sample-list₀ = 0 :: 1 :: 2 :: []

length : {X : Type}  List X  
length []        = zero
length (x :: xs) = suc (length xs)

-- Principle of induction on ℕ
ℕ-elim : {A :   Type}
        A zero -- base case
        ((k : )  A k  A (suc k)) -- induction step
        (n : )  A n
ℕ-elim {A} a₀ f = h
 where
  h : (n : )  A n
  h zero    = a₀
  h (suc n) = f n IH
   where
    IH : A n
    IH = h n

ℕ-elim' : {A :   Type}
        A zero -- base case
        ((k : )  A k  A (suc k)) -- induction step
        (n : )  A n
ℕ-elim' {A} a₀ f zero    = a₀
ℕ-elim' {A} a₀ f (suc n) = f n (ℕ-elim' a₀ f n)

List-elim : {X : Type} (A : List X  Type)
           A [] -- base
           ((x : X) (xs : List X)  A xs  A (x :: xs)) -- step
           (xs : List X)  A xs
List-elim {X} A a f = h
 where
  h : (xs : List X)  A xs
  h []        = a -- base
  h (x :: xs) = f x xs (h xs) -- step

-- \b0
data 𝟘 : Type where

-- \b1
data 𝟙 : Type where
  : 𝟙  -- \star

_≣_ :     Type
zero   zero  = 𝟙
zero   suc y = 𝟘
suc x  zero  = 𝟘
suc x  suc y = x  y

infix 0 _≣_

ℕ-refl : (x : )  x  x
ℕ-refl zero    = 
ℕ-refl (suc x) = ℕ-refl x

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

infixr 20 _+_

_++_ : {A : Type}  List A  List A  List A
[]        ++ ys = ys
(x :: xs) ++ ys = x :: (xs ++ ys)

lh : {X : Type} (xs ys : List X)
    length (xs ++ ys)  length xs + length ys
lh [] ys        = ℕ-refl (length ys)
lh (x :: xs) ys = IH
 where
  IH : length (xs ++ ys)  (length xs + length ys)
  IH = lh xs ys