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 (Nil) = default
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