```module Demo where

data Bool : Set where
True : Bool
False : Bool

not : Bool -> Bool
not False = True
not True = False

idBool : Bool → Bool
idBool = λ b → b

cond : Bool -> Bool -> Bool -> Bool
cond False t e = e
cond True t e = t

if_then_else_ : Bool -> Bool -> Bool -> Bool
if False then t else e = e
if True then t else e = t

test : Bool
test = if True then False else True

data ℕ : Set where
Zero : ℕ
Succ : (k : ℕ) -> ℕ

two = Succ (Succ Zero)

{-# BUILTIN NATURAL ℕ #-}

three = 3

id : {a : Set} -> a -> a
id {a} x = x

idTrue = id True
idThree = id {ℕ} three

data List (a : Set) : Set where
Nil : List a
Cons : a -> List a -> List a

{-
data List :: * -> * where
Nil : List a
Cons : a -> List a -> List a
-}

length : {a : Set} -> List a -> ℕ
length Nil = Zero
length (Cons x xs) = Succ (length xs)

_++_ : {a : Set} -> List a -> List a -> List a
Nil ++ ys = ys
Cons x xs ++ ys = Cons x (xs ++ ys)

head : {a : Set} -> a -> List a -> a
head default (Cons x xs) = x

data Vec (a : Set) : ℕ -> Set where
Nil  : Vec a Zero
Cons : {n : ℕ} -> a -> Vec a n -> Vec a (Succ n)

vhead : ∀ {a n} -> Vec a (Succ n) -> a
vhead (Cons x xs) = x

_+_ : ℕ → ℕ → ℕ
Zero + n = n
Succ m + n = Succ (m + n)

vappend : ∀ {n m a} -> Vec a n -> Vec a m -> Vec a (n + m)
vappend {Zero} Nil ys = ys
vappend {Succ n} (Cons x xs) ys = Cons x (vappend xs ys)

--foo : ∀ {a n} -> Vec a (baz n) -> a
--foo xs = {!xs!}

-- lookup : ∀ {a} -> List a -> ℕ -> a
-- lookup Nil Zero = {!?!}
-- lookup (Cons x xs) Zero = x
-- lookup Nil (Succ n) = {!?!}
-- lookup (Cons x xs) (Succ n) = lookup xs n

data _<_ : ℕ -> ℕ -> Set where
Base : forall {n} -> 0 < Succ n
Step : forall {n m} -> n < m -> Succ n < Succ m

testLT : 3 < 5
testLT = Step (Step (Step Base))

vlookup : forall {a m} -> Vec a m -> (n : ℕ) -> n < m -> a
vlookup Nil n ()
vlookup (Cons x xs) Zero p = x
vlookup (Cons x xs) (Succ n) (Step p) = vlookup xs n p

data Fin : ℕ -> Set where
FZero : forall {n} -> Fin (Succ n)
FSucc : forall {n} -> Fin n -> Fin (Succ n)

--Int32 : Set
--Int32 = Fin (2 ^ 32)

finlookup : forall {a m} -> Vec a m -> Fin m -> a
finlookup (Cons x xs) FZero = x
finlookup (Cons x xs) (FSucc i) = finlookup xs i

finlookup' : forall {a m} -> Vec a m -> Fin m -> a
finlookup' Nil ()
finlookup' (Cons x xs) FZero = x
finlookup' (Cons x xs) (FSucc i) = finlookup' xs i

data Empty : Set where

exfalso : Empty -> {a : Set} -> a
exfalso ()

data _==_ {a : Set} (x : a) : a -> Set where
Refl : x == x

data Either (a b : Set) : Set where
Inl : a -> Either a b
Inr : b -> Either a b

--data EqualNat (x : ℕ) : ℕ -> Set where
---  Yes : {y : ℕ} ->  x == y -> EqualNat x y
--  No : {y : ℕ} -> (x == y -> Empty) -> EqualNat x y

lemma1 : {y : ℕ} -> Zero == Succ y -> Empty
lemma1 ()

succInj : ∀ {x y} -> Succ x == Succ y -> x == y
succInj Refl = Refl

recurseEqual : ∀ {x y} -> Either (x == y) (x == y -> Empty) -> Either (Succ x == Succ y) (Succ x == Succ y → Empty)
recurseEqual (Inl Refl) = Inl Refl
recurseEqual (Inr p) = Inr (\eq -> p (succInj eq))

equal? : (x y : ℕ) -> Either (x == y) (x == y -> Empty)
equal? Zero Zero = Inl Refl
equal? Zero (Succ y) = Inr lemma1
equal? (Succ x) Zero = Inr (λ ())
--equal? (Succ x) (Succ y) = recurseEqual (equal? x y)
equal? (Succ x) (Succ y) with equal? x y
equal? (Succ x) (Succ .x) | Inl Refl = Inl Refl
equal? (Succ x) (Succ y) | Inr x₁ = Inr (\eq -> x₁ (succInj eq))

filter : {a : Set} -> (a -> Bool) -> List a -> List a
filter p Nil = Nil
filter p (Cons x xs) with p x
filter p (Cons x xs) | True = Cons x (filter p xs)
filter p (Cons x xs) | False = filter p xs

congSucc : ∀ {x y} -> x == y -> Succ x == Succ y
congSucc Refl = Refl

cong : {a b : Set} {x y : a} -> (f : a -> b) -> x == y -> f x  == f y
cong f Refl = Refl

plusZero : (n : ℕ) -> (n + 0) == n
plusZero Zero = Refl
plusZero (Succ n) = cong Succ (plusZero n)

trans : {a : Set} {x y z : a} -> x == y -> y == z -> x == z
trans Refl q = q

sym : {a : Set} {x y : a} -> x == y -> y == x
sym Refl = Refl

infixr 2 _<_>_
_<_>_ : {a : Set} -> (x : a) -> {y z : a} -> x == y -> y == z -> x == z
x < p > q = trans p q

_QED : {a : Set} (x : a) -> x == x
_QED x = Refl

plusZero' : (x : ℕ) -> (x + 0) == x
plusZero' Zero = Refl
plusZero' (Succ x) =
(Succ x) + 0
< Refl >
Succ (x + 0)
< cong Succ (plusZero' x) >
Succ x
QED

data Sublist {a : Set} : List a -> List a -> Set where
Base : {xs : List a} -> Sublist Nil xs
Keep : {xs ys : List a} {x : a} -> Sublist xs ys -> Sublist (Cons x xs) (Cons x ys)
Drop : {xs ys : List a} {x : a} -> Sublist xs ys -> Sublist xs (Cons x ys)

filterSublist : {a : Set} (p : a -> Bool) (xs : List a) -> Sublist (filter p xs) xs
filterSublist p Nil = Base
filterSublist p (Cons x xs) with p x
filterSublist p (Cons x xs) | True = Keep (filterSublist p xs)
filterSublist p (Cons x xs) | False = Drop (filterSublist p xs)

-- data _==_ {a : Set} : a -> a -> Set where
--   Refl : {x : a} -> x == x

-- trans : {a : Set} -> {x y z : a} -> x == y -> y == z -> x  == z
-- trans Refl p = p

-- infixr 2 _<_>_
-- _<_>_ : {a : Set} -> (x : a) -> {y z : a} -> x == y -> y == z -> x == z
-- x < p > q = trans p q

-- _QED : {a : Set} (x : a) -> x == x
-- _QED x = Refl

```