data InfIO : Type where
  Do : IO a
      -> (a -> Inf InfIO)
      -> InfIO

{-loopPrint : String -> InfIO
loopPrint msg = Do (putStrLn msg)
                   (\_ => loopPrint msg)-}

{-run : InfIO -> IO ()
run (Do action cont) = do res <- action
                          run (cont res)-}

{-data Fuel = Dry | More Fuel-}
data Fuel = Dry | More (Lazy Fuel)

forever : Fuel
forever = More forever

tank : Nat -> Fuel
tank Z = Dry
tank (S k) = More (tank k)

run : Fuel -> InfIO -> IO ()
run Dry y = putStrLn "Out of fuel"
run (More fuel) (Do c f) = do res <- c
                              run fuel (f res)

(>>=) : IO a -> (a -> Inf InfIO) -> InfIO
(>>=) = Do
loopPrint : String -> InfIO
loopPrint msg = do putStrLn msg
                   loopPrint msg


module Main

import Pruviloj

infixl 9 .>
(.>) : (a -> b) -> (b -> c) -> (a -> c)
(.>) f g = \x => g (f x)

IdempotencyProof : {X : Type} -> (X -> X -> X) -> Type
IdempotencyProof {X} f = (a : X) -> f a a = a

AssociativityProof : {X : Type} -> (X -> X -> X) -> Type
AssociativityProof {X} f = (a : X) ->
                           (b : X) ->
                           (c : X) ->
                           f a (f b c) = f (f a b) c

CommutativityProof : {X : Type} -> (X -> X -> X) -> Type
CommutativityProof {X} f = (a : X) ->
                           (b : X) ->
                           f a b = f b a

LeftUnitalityProof : {X : Type} -> (X -> X -> X) -> X -> Type
LeftUnitalityProof {X} f e = (a : X) -> a = f e a

RightUnitalityProof : {X : Type} -> (X -> X -> X) -> X -> Type
RightUnitalityProof {X} f e = (a : X) -> a = f a e

UnitalityProof : {X : Type} -> (X -> X -> X) -> X -> Type
UnitalityProof {X} f e = (a : X) -> (a = f e a, a = f a e)

record Dual (X : Type) where
  constructor MkDual
  fromDual : X

implementation (Eq x) => Eq (Dual x) where {
  (MkDual x) == (MkDual y) = (x == y)
}

dualInj : (x = y) -> (MkDual x = MkDual y)
dualInj Refl = Refl

interface (Eq X) => MeetSemiLattice (X : Type)
          where {
            meet : X -> X -> X
            meetIsIdempotent  : IdempotencyProof   meet
            meetIsAssociative : AssociativityProof meet
            meetIsCommutative : CommutativityProof meet
          }

interface (Eq X) => JoinSemiLattice (X : Type)
          where {
            join : X -> X -> X
            joinIsIdempotent  : IdempotencyProof   join
            joinIsAssociative : AssociativityProof join
            joinIsCommutative : CommutativityProof join
          }

implementation (JoinSemiLattice t) => MeetSemiLattice (Dual t) where {
  meet a b = MkDual $ join (fromDual a) (fromDual b)
  meetIsIdempotent (MkDual a)
    = dualInj $ joinIsIdempotent a
  meetIsAssociative (MkDual a) (MkDual b) (MkDual c)
    = dualInj $ joinIsAssociative a b c
  meetIsCommutative (MkDual a) (MkDual b)
    = dualInj $ joinIsCommutative a b
}

implementation (MeetSemiLattice t) => JoinSemiLattice (Dual t) where {
  join a b = MkDual $ meet (fromDual a) (fromDual b)
  joinIsIdempotent (MkDual a)
    = dualInj $ meetIsIdempotent a
  joinIsAssociative (MkDual a) (MkDual b) (MkDual c)
    = dualInj $ meetIsAssociative a b c
  joinIsCommutative (MkDual a) (MkDual b)
    = dualInj $ meetIsCommutative a b
}

interface (MeetSemiLattice X)
          => BoundedMeetSemiLattice (X : Type)
          where {
            top : X
            topIsUnital : UnitalityProof meet top
          }

interface (JoinSemiLattice X)
          => BoundedJoinSemiLattice (X : Type)
          where {
            bot : X
            botIsUnital : UnitalityProof join bot
          }

implementation (BoundedMeetSemiLattice t) => BoundedJoinSemiLattice (Dual t)
               where {
                 bot = MkDual top
                 botIsUnital (MkDual a) = let (p1, p2) = topIsUnital a
                                          in (dualInj p1, dualInj p2)
               }

interface (MeetSemiLattice X, JoinSemiLattice X)
          => Lattice (X : Type)
          where {}

interface (BoundedMeetSemiLattice X, BoundedJoinSemiLattice X)
          => BoundedLattice (X : Type)
          where {}

interface (BoundedLattice X)
          => CompleteLattice (X : Type)
          where {
            arbJoin : (I : Type) -> (I -> X) -> X
            arbMeet : (I : Type) -> (I -> X) -> X
            -- LAWS???
          }

ltFromMSL : (M : Type) -> (MeetSemiLattice M) => M -> M -> Bool
ltFromMSL = ?fixme1

interface (MeetSemiLattice X, MeetSemiLattice Y)
          => MonotoneFunction (X : Type) (Y : Type) (f : X -> Y)
          where {
            isMonotone : (a : X) ->
                         (b : X) ->
                         ltFromMSL X a b = ltFromMSL Y (f a) (f b)
          }

implementation (X : Type, CompleteLattice X, MonotoneFunction X X f)
               => CompleteLattice (a : X ** (a = f a))
               where {
               }

main : IO ()
main = pure ()


module Main

import Data.Fin
import Data.Vect
import Data.Vect.Quantifiers
import Decidable.Equality

Cell : Nat -> Type
Cell n = Maybe (Fin n)

data Board : Nat -> Type where
  MkBoard : {n : Nat} -> Vect n (Vect n (Cell n)) -> Board n

emptyBoard : {n : Nat} -> Board n
emptyBoard {n=n} = MkBoard (replicate n (replicate n Nothing))

Empty : Cell n -> Type
Empty {n=n} x = (the (Cell n) Nothing) = x

Filled : Cell n -> Type
Filled {n=n} = (\x => Not (Empty x))

FullBoard : Board n -> Type
FullBoard (MkBoard b) = All (All Filled) b

indexStep : {i : Fin n} -> {xs : Vect n a} -> {x : a} -> index i xs = index (FS i) (x::xs)
indexStep = Refl

find : {p : a -> Type} -> ((x : a) -> Dec (p x)) -> (xs : Vect n a)
       -> Either (All (\x => Not (p x)) xs) (y : a ** (p y, (i : Fin n ** y = index i xs)))
find _ Nil = Left Nil
find {p} d (x::xs) with (d x)
  | Yes prf = Right (x ** (prf, (FZ ** Refl)))
  | No prf =
    case find {p} d xs of
      Right (y ** (prf', (i ** prf''))) =>
        Right (y ** (prf', (FS i ** replace {P=(\x => y = x)} (indexStep {x=x}) prf'')))
      Left prf' => Left (prf::prf')

empty : (cell : Cell n) -> Dec (Empty cell)
empty Nothing = Yes Refl
empty (Just _) = No nothingNotJust

findEmptyInRow : (xs : Vect n (Cell n)) -> Either (All Filled xs) (i : Fin n ** Empty (index i xs))
findEmptyInRow xs =
  case find {p=Empty} empty xs of
    Right (_ ** (pempty, (i ** pidx))) => Right (i ** trans pempty pidx)
    Left p => Left p

getCell : Board n -> (Fin n, Fin n) -> Cell n
getCell (MkBoard b) (x, y) = index x (index y b)

emptyCell : {n : Nat} -> (b : Board n) ->
         Either (FullBoard b) (c : (Fin n, Fin n) ** Empty (getCell b c))
emptyCell (MkBoard rs) =
  case helper rs of
    Left p => Left p
    Right (ri ** (ci ** pf2)) => Right ((ci, ri) ** pf2)
 where
  helper : (rs : Vect m (Vect n (Cell n)))
           -> Either (All (All Filled) rs) (r : Fin m ** (c : Fin n ** Empty (index c (index r rs))))
  helper Nil = Left Nil
  helper (r::rs) =
    case findEmptyInRow r of
      Right (ci ** pf3) => Right (FZ ** (ci ** pf3))
      Left prf =>
        case helper rs of
          Left prf' => Left (prf::prf')
          Right (ri ** (ci ** pf4)) => Right (FS ri ** (ci ** pf4))

main : IO ()
main =
  case emptyCell (emptyBoard {n=0}) of
    Left _ => putStrLn "l"
    Right _ => putStrLn "r"


zipWithS : (f : a -> b -> c) -> Stream a -> Stream b -> Stream c
zipWithS f (x :: xs) (y :: ys) = f x y :: zipWithS f xs ys

partial
fib : Stream Nat
fib = 0 :: zipWithS (+) fib (1 :: fib)

partial main : IO ()
main = printLn (take 15 fib)


module Sub03Apply54x30

import ProofColDivSeqBase
import ProofColDivSeqPostulate
import ProofColDivSeqPostuProof

%default total
-- %language ElabReflection

-- 3(18x+10) --A[6,-4]->C[4,-4]--> 3(8x+3)
export
apply54x30 : (Not . P) (S (S (S (plus (plus (plus (plus (plus l l) l) (S (plus (plus l l) l))) (S (S (plus (plus (plus l l) l) (S (plus (plus l l) l))))))
                         (S (S (plus (plus (plus l l) l) (S (plus (plus l l) l)))))))))
  -> (m : Nat **
        (LTE (S m)
             (S (S (S (plus (plus (plus (plus (plus l l) l) (S (plus (plus l l) l))) (S (S (plus (plus (plus l l) l) (S (plus (plus l l) l))))))
                            (S (S (plus (plus (plus l l) l) (S (plus (plus l l) l))))))))),
         (Not . P) m))
apply54x30 {l} col = ((S (S (S (plus (plus (plus l l) (plus l l)) (plus (plus l l) (plus l l)))))) ** (lte54x30 l, ac54x30To24x9 l col)) where
  lte54x30 : (l:Nat) -> LTE (S (S (S (S (plus (plus (plus l l) (plus l l)) (plus (plus l l) (plus l l)))))))
                            (S (S (S (plus (plus (plus (plus (plus l l) l) (S (plus (plus l l) l))) (S (S (plus (plus (plus l l) l) (S (plus (plus l l) l))))))
                                           (S (S (plus (plus (plus l l) l) (S (plus (plus l l) l)))))))))
  lte54x30 Z = (lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . LTESucc . LTESucc . LTESucc . LTESucc) LTEZero
  lte54x30 (S k) = let lemma = lte54x30 k in
    rewrite (sym (plusSuccRightSucc k k)) in
    rewrite (sym (plusSuccRightSucc (plus k k) (S (plus k k)))) in
    rewrite (sym (plusSuccRightSucc (plus k k) (plus k k))) in
    rewrite (sym (plusSuccRightSucc (plus (plus k k) (plus k k)) (S (S (S (plus (plus k k) (plus k k))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus k k) (plus k k)) (S (S (plus (plus k k) (plus k k)))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus k k) (plus k k)) (S (plus (plus k k) (plus k k))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus k k) (plus k k)) (plus (plus k k) (plus k k)))) in
    rewrite (sym (plusSuccRightSucc (plus k k) k)) in
    rewrite (sym (plusSuccRightSucc (plus (plus k k) k) (S (S (S (plus (plus k k) k)))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus k k) k) (S (S (plus (plus k k) k))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus k k) k) (S (plus (plus k k) k)))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus k k) k) (S (plus (plus k k) k))) (S (S (S (S (S (S (S (plus (plus (plus k k) k) (S (plus (plus k k) k)))))))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus k k) k) (S (plus (plus k k) k))) (S (S (S (S (S (S (plus (plus (plus k k) k) (S (plus (plus k k) k))))))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus k k) k) (S (plus (plus k k) k))) (S (S (S (S (S (plus (plus (plus k k) k) (S (plus (plus k k) k)))))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus k k) k) (S (plus (plus k k) k))) (S (S (S (S (plus (plus (plus k k) k) (S (plus (plus k k) k))))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus k k) k) (S (plus (plus k k) k))) (S (S (S (plus (plus (plus k k) k) (S (plus (plus k k) k)))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus k k) k) (S (plus (plus k k) k))) (S (S (plus (plus (plus k k) k) (S (plus (plus k k) k))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus (plus k k) k) (S (plus (plus k k) k))) (S (S (plus (plus (plus k k) k) (S (plus (plus k k) k))))))  (S (S (S (S (S (S (S (plus (plus (plus k k) k) (S (plus (plus k k) k)))))))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus (plus k k) k) (S (plus (plus k k) k))) (S (S (plus (plus (plus k k) k) (S (plus (plus k k) k))))))  (S (S (S (S (S (S (plus (plus (plus k k) k) (S (plus (plus k k) k))))))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus (plus k k) k) (S (plus (plus k k) k))) (S (S (plus (plus (plus k k) k) (S (plus (plus k k) k))))))  (S (S (S (S (S (plus (plus (plus k k) k) (S (plus (plus k k) k)))))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus (plus k k) k) (S (plus (plus k k) k))) (S (S (plus (plus (plus k k) k) (S (plus (plus k k) k))))))  (S (S (S (S (plus (plus (plus k k) k) (S (plus (plus k k) k))))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus (plus k k) k) (S (plus (plus k k) k))) (S (S (plus (plus (plus k k) k) (S (plus (plus k k) k))))))  (S (S (S (plus (plus (plus k k) k) (S (plus (plus k k) k)))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus (plus k k) k) (S (plus (plus k k) k))) (S (S (plus (plus (plus k k) k) (S (plus (plus k k) k))))))  (S (S (plus (plus (plus k k) k) (S (plus (plus k k) k))))))) in
      (lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . LTESucc . LTESucc . LTESucc . LTESucc . LTESucc . LTESucc . LTESucc . LTESucc) lemma


module Data.So

import Data.Bool

%default total

||| Ensure that some run-time Boolean test has been performed.
|||
||| This lifts a Boolean predicate to the type level. See the function `choose`
||| if you need to perform a Boolean test and convince the type checker of this
||| fact.
|||
||| If you find yourself using `So` for something other than primitive types,
||| it may be appropriate to define a type of evidence for the property that you
||| care about instead.
public export
data So : Bool -> Type where
  Oh : So True

export
Uninhabited (So False) where
  uninhabited Oh impossible

||| Perform a case analysis on a Boolean, providing clients with a `So` proof
export
choose : (b : Bool) -> Either (So b) (So (not b))
choose True  = Left Oh
choose False = Right Oh

export
eqToSo : b = True -> So b
eqToSo Refl = Oh

export
soToEq : So b -> b = True
soToEq Oh = Refl

||| If `b` is True, `not b` can't be True
export
soToNotSoNot : So b -> Not (So (not b))
soToNotSoNot Oh = uninhabited

||| If `not b` is True, `b` can't be True
export
soNotToNotSo : So (not b) -> Not (So b)
soNotToNotSo = flip soToNotSoNot

export
soAnd : {a : Bool} -> So (a && b) -> (So a, So b)
soAnd soab with (choose a)
  soAnd {a=True}  soab | Left Oh = (Oh, soab)
  soAnd {a=True}  soab | Right prf = absurd prf
  soAnd {a=False} soab | Right prf = absurd soab

export
andSo : (So a, So b) -> So (a && b)
andSo (Oh, Oh) = Oh

export
soOr : {a : Bool} -> So (a || b) -> Either (So a) (So b)
soOr soab with (choose a)
  soOr {a=True}  _    | Left Oh = Left Oh
  soOr {a=False} _    | Left Oh impossible
  soOr {a=False} soab | Right Oh = Right soab
  soOr {a=True}  _    | Right Oh impossible

export
orSo : Either (So a) (So b) -> So (a || b)
orSo (Left Oh)  = Oh
orSo (Right Oh) = rewrite orTrueTrue a in
                  Oh


||| http://okmij.org/ftp/Computation/free-monad.html
module Freer

%default total
%access public export

||| Argh, has the same totality problems as free monad!
data FFree : (Type -> Type) -> Type -> Type where
  FPure   : a -> FFree g a
  FImpure : g x -> (x -> FFree g a) -> FFree g a

fmap : (a -> b) -> FFree g a -> FFree g b
fmap f (FPure x)     = FPure (f x)
fmap f (FImpure u q) = FImpure u (fmap f . q)

Functor (FFree g) where
  map f (FPure x)     = FPure (f x)
  map f (FImpure u q) = FImpure u (map f . q)

Applicative (FFree g) where
  pure = FPure
  (FPure f) <*> x = map f x
  (FImpure u q) <*> x = FImpure u ((<*> x) . q)

infixr 5 >=>

(>=>) : Monad m => (a -> m b) -> (b -> m c) -> (a -> m c)
f >=> g = (>>= g) . f

Monad (FFree g) where
  (FPure x) >>= f = f x
  (FImpure u f') >>= f = FImpure u (f' >=> f)


module Data.Bool.Extra

%default total

public export
andSameNeutral : (x : Bool) -> x && x = x
andSameNeutral False = Refl
andSameNeutral True = Refl

public export
andFalseFalse : (x : Bool) -> x && False = False
andFalseFalse False = Refl
andFalseFalse True = Refl

public export
andTrueNeutral : (x : Bool) -> x && True = x
andTrueNeutral False = Refl
andTrueNeutral True = Refl

public export
orSameNeutral : (x : Bool) -> x || x = x
orSameNeutral False = Refl
orSameNeutral True = Refl

public export
orFalseNeutral : (x : Bool) -> x || False = x
orFalseNeutral False = Refl
orFalseNeutral True = Refl

public export
orTrueTrue : (x : Bool) -> x || True = True
orTrueTrue False = Refl
orTrueTrue True = Refl

public export
orSameAndRightNeutral : (x, right : Bool) -> x || (x && right) = x
orSameAndRightNeutral False _ = Refl
orSameAndRightNeutral True _ = Refl

export
anyTrue : List Bool -> Bool
anyTrue [] = False
anyTrue (x :: xs) = x || anyTrue xs

export
allTrue : List Bool -> Bool
allTrue [] = True
allTrue (x :: xs) = x && allTrue xs


%default partial

data Vect : Nat -> Type -> Type where
     Nil  : Vect Z a
     (::) : a -> Vect k a -> Vect (S k) a

append : Vect n a -> Vect m a -> Vect (n + m) a
append [] ys = ys
append (x :: xs) ys = x :: append xs ys

-- Primarily to check the number of cases in the totality checker doesn't
-- explode because of all the Nils and Nats
funny : Vect 4 Bool -> Int
funny [False, False, False, False] = 0
funny [False, False, False, True] = 1
funny [False, False, True, False] = 2
funny [False, False, True, True] = 3
funny [False, True, False, False] = 4
funny [False, True, False, True] = 5
funny [False, True, True, False] = 6
funny [False, True, True, True] = 7
funny [True, False, False, False] = 8
funny [True, False, False, True] = 0
funny [True, False, True, False] = 10
funny [True, False, True, True] = 11
funny [True, True, False, False] = 12
funny [True, True, False, True] = 13
funny [True, True, True, False] = 14
funny [True, True, True, True] = 15

notFunny : Vect 4 Bool -> Int
notFunny [False, False, False, False] = 0
notFunny [False, False, False, True] = 1
notFunny [False, False, True, False] = 2
-- notFunny [False, False, True, True] = 3
notFunny [False, True, False, False] = 4
notFunny [False, True, False, True] = 5
notFunny [False, True, True, False] = 6
-- notFunny [False, True, True, True] = 7
notFunny [True, False, False, False] = 8
notFunny [True, False, False, True] = 0
notFunny [True, False, True, False] = 10
notFunny [True, False, True, True] = 11
notFunny [True, True, False, False] = 12
notFunny [True, True, False, True] = 13
notFunny [True, True, True, False] = 14
notFunny [True, True, True, True] = 15


module Sub14Apply108x72

import ProofColDivSeqBase
import ProofColDivSeqPostulate

%default total
-- %language ElabReflection

-- 3(36x+24) --F[5,-2]->E[2,-4]--> 3(8x+5)
fe108x72To24x15 :
  (o:Nat) ->  P (S (S (S (S (S (S (plus (plus (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))
                                              (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))
                                        (S (S (S (plus (plus (plus (plus o o) o) (S (plus (plus o o) o))) (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))))))
                                  (S (S (S (plus (plus (plus (plus o o) o) (S (plus (plus o o) o))) (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o)))))))))))))))) 2
    -> P (S (S (S (S (S (plus (plus (plus o o) (plus o o)) (plus (plus o o) (plus o o)))))))) 2
fe108x72To24x15 o prf =
  let prf2 = lvDown (S (S (S (S (S (S (plus (plus (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))
                                              (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))
                                        (S (S (S (plus (plus (plus (plus o o) o) (S (plus (plus o o) o))) (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))))))
                                  (S (S (S (plus (plus (plus (plus o o) o) (S (plus (plus o o) o))) (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o)))))))))))))))) 2
                    prf in
    let prf3 = fe108x72To24x15' o prf2 in lvDown (S (S (S (S (S (plus (plus (plus o o) (plus o o)) (plus (plus o o) (plus o o)))))))) 3 prf3

export
apply108x72 : P (S (S (S (S (S (S (plus (plus (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))
                                              (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))
                                        (S (S (S (plus (plus (plus (plus o o) o) (S (plus (plus o o) o))) (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))))))
                                  (S (S (S (plus (plus (plus (plus o o) o) (S (plus (plus o o) o))) (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o)))))))))))))))) 2
  -> (m : Nat **
        (LTE (S m)
             (S (S (S (S (S (S (plus (plus (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))
                                                 (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))
                                           (S (S (S (plus (plus (plus (plus o o) o) (S (plus (plus o o) o))) (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))))))
                                     (S (S (S (plus (plus (plus (plus o o) o) (S (plus (plus o o) o))) (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o)))))))))))))))),
         P m 2))
apply108x72 {o} col = let col2 = fe108x72To24x15 o col in ((S (S (S (S (S (plus (plus (plus o o) (plus o o)) (plus (plus o o) (plus o o))))))))
                                                           ** (lte108x72 o, col2)) where
  lte108x72 : (o:Nat) -> LTE (S (S (S (S (S (S (plus (plus (plus o o) (plus o o)) (plus (plus o o) (plus o o)))))))))
          (S (S (S (S (S (S (plus (plus (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))
                                              (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))
                                        (S (S (S (plus (plus (plus (plus o o) o) (S (plus (plus o o) o))) (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))))))
                                  (S (S (S (plus (plus (plus (plus o o) o) (S (plus (plus o o) o))) (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))))))))))))
  lte108x72 Z = (lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . LTESucc . LTESucc . LTESucc . LTESucc . LTESucc . LTESucc) LTEZero
  lte108x72 (S o) = let lemma = lte108x72 o in

    rewrite (sym (plusSuccRightSucc o o)) in

    rewrite (sym (plusSuccRightSucc (plus o o)  (S (plus o o)))) in
    rewrite (sym (plusSuccRightSucc (plus o o)  (plus o o))) in

    rewrite (sym (plusSuccRightSucc (plus (plus o o) (plus o o))  (S (S (S (plus (plus o o) (plus o o))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus o o) (plus o o))  (S (S (plus (plus o o) (plus o o)))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus o o) (plus o o))  (S (plus (plus o o) (plus o o))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus o o) (plus o o))  (plus (plus o o) (plus o o)))) in

    rewrite (sym (plusSuccRightSucc (plus o o)  o)) in

    rewrite (sym (plusSuccRightSucc (plus (plus o o) o)  (S (S (S (plus (plus o o) o)))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus o o) o)  (S (S (plus (plus o o) o))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus o o) o)  (S (plus (plus o o) o)))) in

    rewrite (sym (plusSuccRightSucc (plus (plus (plus o o) o) (S (plus (plus o o) o)))
              (S (S (S (S (S (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o)))))))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus o o) o) (S (plus (plus o o) o)))
              (S (S (S (S (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus o o) o) (S (plus (plus o o) o)))
              (S (S (S (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o)))))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus o o) o) (S (plus (plus o o) o)))
              (S (S (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus o o) o) (S (plus (plus o o) o)))
              (S (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o)))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus o o) o) (S (plus (plus o o) o)))
              (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))) in

    rewrite (sym (plusSuccRightSucc (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))
                                                                                (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))
              (S (S (S (S (S (S (S (S (S (S (S (S (S (S (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))   (S (S (plus (plus (plus o o) o)
                                      (S (plus (plus o o)
                                               o)))))))))))))))))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))
                                                                                (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))
              (S (S (S (S (S (S (S (S (S (S (S (S (S (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))   (S (S (plus (plus (plus o o) o)
                                      (S (plus (plus o o)
                                               o))))))))))))))))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))
                                                                                (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))
              (S (S (S (S (S (S (S (S (S (S (S (S (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))   (S (S (plus (plus (plus o o) o)
                                      (S (plus (plus o o)
                                               o)))))))))))))))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))
                                                                                (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))
              (S (S (S (S (S (S (S (S (S (S (S (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))   (S (S (plus (plus (plus o o) o)
                                      (S (plus (plus o o)
                                               o))))))))))))))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))
                                                                                (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))
              (S (S (S (S (S (S (S (S (S (S (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))   (S (S (plus (plus (plus o o) o)
                                      (S (plus (plus o o)
                                               o)))))))))))))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))
                                                                                (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))
              (S (S (S (S (S (S (S (S (S (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))   (S (S (plus (plus (plus o o) o)
                                      (S (plus (plus o o)
                                               o))))))))))))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))
                                                                                (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))
              (S (S (S (S (S (S (S (S (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))   (S (S (plus (plus (plus o o) o)
                                      (S (plus (plus o o)
                                               o)))))))))))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))
                                                                                (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))
              (S (S (S (S (S (S (S (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))   (S (S (plus (plus (plus o o) o)
                                      (S (plus (plus o o)
                                               o))))))))))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))
                                                                                (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))
              (S (S (S (S (S (S (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))   (S (S (plus (plus (plus o o) o)
                                      (S (plus (plus o o)
                                               o)))))))))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))
                                                                                (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))
              (S (S (S (S (S (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))   (S (S (plus (plus (plus o o) o)
                                      (S (plus (plus o o)
                                               o))))))))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))
                                                                                (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))
              (S (S (S (S (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))   (S (S (plus (plus (plus o o) o)
                                      (S (plus (plus o o)
                                               o)))))))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))
                                                                                (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))
              (S (S (S (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))   (S (S (plus (plus (plus o o) o)
                                      (S (plus (plus o o)
                                               o))))))))))) in

    rewrite (sym (plusSuccRightSucc (plus (plus (plus (plus (plus o o) o)
                                                           (S (plus (plus o o) o)))
                                                     (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))  (S (S (S (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))   (S (S (plus (plus (plus o o) o)
                                                                          (S (plus (plus o o) o))))))))))
              (S (S (S (S (S (S (S (S (S (S (S (S (S (S (plus (plus (plus (plus o o) o)
                                                          (S (plus (plus o o) o)))
                                                                    (S (S (plus (plus (plus o o) o) (S (plus (plus o o)
                             o)))))))))))))))))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus (plus (plus o o) o)
                                                           (S (plus (plus o o) o)))
                                                     (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))  (S (S (S (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))   (S (S (plus (plus (plus o o) o)
                                                                          (S (plus (plus o o) o))))))))))
              (S (S (S (S (S (S (S (S (S (S (S (S (S (plus (plus (plus (plus o o) o)
                                                          (S (plus (plus o o) o)))
                                                                    (S (S (plus (plus (plus o o) o) (S (plus (plus o o)
                             o))))))))))))))))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus (plus (plus o o) o)
                                                           (S (plus (plus o o) o)))
                                                     (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))  (S (S (S (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))   (S (S (plus (plus (plus o o) o)
                                                                          (S (plus (plus o o) o))))))))))
              (S (S (S (S (S (S (S (S (S (S (S (S (plus (plus (plus (plus o o) o)
                                                          (S (plus (plus o o) o)))
                                                                    (S (S (plus (plus (plus o o) o) (S (plus (plus o o)
                             o)))))))))))))))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus (plus (plus o o) o)
                                                           (S (plus (plus o o) o)))
                                                     (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))  (S (S (S (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))   (S (S (plus (plus (plus o o) o)
                                                                          (S (plus (plus o o) o))))))))))
              (S (S (S (S (S (S (S (S (S (S (S (plus (plus (plus (plus o o) o)
                                                          (S (plus (plus o o) o)))
                                                                    (S (S (plus (plus (plus o o) o) (S (plus (plus o o)
                             o))))))))))))))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus (plus (plus o o) o)
                                                           (S (plus (plus o o) o)))
                                                     (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))  (S (S (S (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))   (S (S (plus (plus (plus o o) o)
                                                                          (S (plus (plus o o) o))))))))))
              (S (S (S (S (S (S (S (S (S (S (plus (plus (plus (plus o o) o)
                                                          (S (plus (plus o o) o)))
                                                                    (S (S (plus (plus (plus o o) o) (S (plus (plus o o)
                             o)))))))))))))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus (plus (plus o o) o)
                                                           (S (plus (plus o o) o)))
                                                     (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))  (S (S (S (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))   (S (S (plus (plus (plus o o) o)
                                                                          (S (plus (plus o o) o))))))))))
              (S (S (S (S (S (S (S (S (S (plus (plus (plus (plus o o) o)
                                                          (S (plus (plus o o) o)))
                                                                    (S (S (plus (plus (plus o o) o) (S (plus (plus o o)
                             o))))))))))))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus (plus (plus o o) o)
                                                           (S (plus (plus o o) o)))
                                                     (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))  (S (S (S (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))   (S (S (plus (plus (plus o o) o)
                                                                          (S (plus (plus o o) o))))))))))
              (S (S (S (S (S (S (S (S (plus (plus (plus (plus o o) o)
                                                          (S (plus (plus o o) o)))
                                                                    (S (S (plus (plus (plus o o) o) (S (plus (plus o o)
                             o)))))))))))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus (plus (plus o o) o)
                                                           (S (plus (plus o o) o)))
                                                     (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))  (S (S (S (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))   (S (S (plus (plus (plus o o) o)
                                                                          (S (plus (plus o o) o))))))))))
              (S (S (S (S (S (S (S (plus (plus (plus (plus o o) o)
                                                          (S (plus (plus o o) o)))
                                                                    (S (S (plus (plus (plus o o) o) (S (plus (plus o o)
                             o))))))))))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus (plus (plus o o) o)
                                                           (S (plus (plus o o) o)))
                                                     (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))  (S (S (S (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))   (S (S (plus (plus (plus o o) o)
                                                                          (S (plus (plus o o) o))))))))))
              (S (S (S (S (S (S (plus (plus (plus (plus o o) o)
                                                          (S (plus (plus o o) o)))
                                                                    (S (S (plus (plus (plus o o) o) (S (plus (plus o o)
                             o)))))))))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus (plus (plus o o) o)
                                                           (S (plus (plus o o) o)))
                                                     (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))  (S (S (S (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))   (S (S (plus (plus (plus o o) o)
                                                                          (S (plus (plus o o) o))))))))))
              (S (S (S (S (S (plus (plus (plus (plus o o) o)
                                                          (S (plus (plus o o) o)))
                                                                    (S (S (plus (plus (plus o o) o) (S (plus (plus o o)
                             o))))))))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus (plus (plus o o) o)
                                                           (S (plus (plus o o) o)))
                                                     (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))  (S (S (S (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))   (S (S (plus (plus (plus o o) o)
                                                                          (S (plus (plus o o) o))))))))))
              (S (S (S (S (plus (plus (plus (plus o o) o)
                                                          (S (plus (plus o o) o)))
                                                                    (S (S (plus (plus (plus o o) o) (S (plus (plus o o)
                             o)))))))))))) in
    rewrite (sym (plusSuccRightSucc (plus (plus (plus (plus (plus o o) o)
                                                           (S (plus (plus o o) o)))
                                                     (S (S (plus (plus (plus o o) o) (S (plus (plus o o) o))))))  (S (S (S (plus (plus (plus (plus o o) o) (S (plus (plus o o) o)))   (S (S (plus (plus (plus o o) o)
                                                                          (S (plus (plus o o) o))))))))))
              (S (S (S (plus (plus (plus (plus o o) o)
                                                          (S (plus (plus o o) o)))
                                                                    (S (S (plus (plus (plus o o) o) (S (plus (plus o o)
                             o))))))))))) in

      (lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . lteSuccRight . LTESucc . LTESucc . LTESucc . LTESucc . LTESucc . LTESucc . LTESucc . LTESucc) lemma


module Equivalence

-- Proof that small-step and big-step semantics for
-- the simply-typed lambda calculus are equivalent.

import BigStep
import Step
import Subst
import Term

%default total
%access export

--------------------------
-- Begin: STEP => BIG-STEP

stepToBigStep : Step e1 e2 -> BigStep e2 e3 ->
                BigStep e1 e3
-- case split in the following order: (Step e1 e2), (BigStep e2 e3)
stepToBigStep (StApp1 x) (BStValue v) impossible
--
stepToBigStep (StApp1 x) (BStApp w s1 t1) = let ih = stepToBigStep x w
                                            in BStApp ih s1 t1
--
stepToBigStep (StApp2 x z) (BStValue v) impossible
--
stepToBigStep (StApp2 x z) (BStApp s1 t1 u) = let ih = stepToBigStep z t1
                                              in BStApp s1 ih u
--
stepToBigStep (StBeta x) y = BStApp (BStValue VAbs) (BStValue x) y
--
stepToBigStep (StFix x) (BStValue v) impossible
--
stepToBigStep (StFix x) (BStFix z w) = let ih = stepToBigStep x z
                                       in BStFix ih w
--
stepToBigStep StFixBeta y = BStFix (BStValue VAbs) y
--
stepToBigStep (StSucc x) (BStValue v) = case v of
  VAbs     impossible
  VZero    impossible
  VSucc v' => BStSucc $ stepToBigStep x (BStValue v')
--
stepToBigStep (StSucc x) (BStSucc y) = BStSucc $ stepToBigStep x y
--
stepToBigStep (StPred x) (BStValue v) impossible
--
stepToBigStep (StPred x) (BStPredZero z) = BStPredZero $ stepToBigStep x z
--
stepToBigStep (StPred x) (BStPredSucc y) = let ih = stepToBigStep x y
                                           in BStPredSucc ih
--
stepToBigStep StPredZero (BStValue v) = BStPredZero (BStValue VZero)
--
stepToBigStep (StPredSucc x) y = BStPredSucc (BStSucc y)
--
stepToBigStep (StIfz x) (BStValue v) impossible
--
stepToBigStep (StIfz x) (BStIfzZero z w) = let ih = stepToBigStep x z
                                           in BStIfzZero ih w
--
stepToBigStep (StIfz x) (BStIfzSucc w s) = let ih = stepToBigStep x w
                                           in BStIfzSucc ih s
--
stepToBigStep StIfzZero y = BStIfzZero (BStValue VZero) y
--
stepToBigStep (StIfzSucc x) y = BStIfzSucc (BStValue (VSucc x)) y

-- End: STEP => BIG-STEP
------------------------

-------------------------------
-- Begin: TRANSSTEP => BIG-STEP

transStepToBigStep : (TransStep e1 e2) -> (v : Value e2) ->
                     BigStep e1 e2
transStepToBigStep (TStRefl _)    v = BStValue v
transStepToBigStep (TStTrans x y) v = let ih = transStepToBigStep y v
                                      in stepToBigStep x ih

-- End: TRANSSTEP => BIG-STEP
-----------------------------

-------------------------------
-- Begin: BIG-STEP => TRANSSTEP

-- Congruence lemma for '(TApp _ e)':
congApp1 : TransStep e1 e2 -> TransStep (TApp e1 e) (TApp e2 e)
congApp1 (TStRefl e1)   = TStRefl (TApp e1 _)
congApp1 (TStTrans x y) = TStTrans (StApp1 x) (congApp1 y)

-- Congruence lemma for '(TApp e _)':
congApp2 : {v : Value e} ->
           TransStep e1 e2 -> TransStep (TApp e e1) (TApp e e2)
congApp2         (TStRefl e1)   = TStRefl (TApp _ e1)
congApp2 {v = v} (TStTrans x y) = TStTrans (StApp2 v x) (congApp2 {v = v} y)

-- Congruence lemma for '(Fix _)':
total congFix : TransStep e1 e2 -> TransStep (TFix e1) (TFix e2)
congFix (TStRefl e1)   = TStRefl (TFix e1)
congFix (TStTrans x y) = TStTrans (StFix x) (congFix y)

-- Congruence lemma for '(Succ _)':
congSucc : TransStep e1 e2 -> TransStep (TSucc e1) (TSucc e2)
congSucc (TStRefl e1)   = TStRefl (TSucc e1)
congSucc (TStTrans x y) = TStTrans (StSucc x) (congSucc y)

-- Congruence lemma for '(Pred _)':
congPred : TransStep e1 e2 -> TransStep (TPred e1) (TPred e2)
congPred (TStRefl e1)   = TStRefl (TPred e1)
congPred (TStTrans x y) = TStTrans (StPred x) (congPred y)

-- Congruence lemma for '(Ifz _ ez es)':
congIfz : TransStep e1 e2 -> TransStep (TIfz e1 ez es) (TIfz e2 ez es)
congIfz (TStRefl e1)   = TStRefl (TIfz e1 _ _)
congIfz (TStTrans x y) = TStTrans (StIfz x) (congIfz y)

bigStepToTransStep : BigStep e1 e2 -> (TransStep e1 e2, Value e2)
--
bigStepToTransStep (BStValue v) = (TStRefl _, v)
--
bigStepToTransStep (BStApp z w t1) =
  let (tst1, v1) = bigStepToTransStep z
      (tst2, v2) = bigStepToTransStep w
      (tst3, v3) = bigStepToTransStep t1
      tst = (congApp1 tst1) .++. (congApp2 {v = VAbs} tst2) .+. (StBeta v2) .++. tst3
  in (tst, v3)
--
bigStepToTransStep (BStFix y z) =
  let (tst1, v1) = bigStepToTransStep y
      (tst2, v2) = bigStepToTransStep z
      tst = (congFix tst1) .+. StFixBeta .++. tst2
  in (tst, v2)
--
bigStepToTransStep (BStSucc x) =
  let (tst1, v1) = bigStepToTransStep x
  in (congSucc tst1, VSucc v1)
--
bigStepToTransStep (BStPredZero y) =
  let (tst1, v1) = bigStepToTransStep y
      tst = congPred tst1 .+. StPredZero
  in (tst, VZero)
--
bigStepToTransStep (BStPredSucc x) =
  let (tst1, VSucc v1) = bigStepToTransStep x
      tst = (congPred tst1) .+. (StPredSucc v1)
  in (tst, v1)

bigStepToTransStep (BStIfzZero z w) =
  let (tst1, v1) = bigStepToTransStep z
      (tst2, v2) = bigStepToTransStep w
      tst = (congIfz tst1) .+. StIfzZero .++. tst2
  in (tst, v2)

bigStepToTransStep (BStIfzSucc w s) =
  let (tst1, VSucc v1) = bigStepToTransStep w
      (tst2, v2) = bigStepToTransStep s
      tst = (congIfz tst1) .+. (StIfzSucc v1) .++. tst2
  in (tst, v2)

-- End: BIG-STEP => TRANSSTEP
-----------------------------

-------------------------------------
-- Begin: CO-BIG-STEP => CO-TRANSSTEP

-- The relations 'CoTransStep' and 'CoBigStep' are not equivalent;
-- only one direction of the equivalence holds. To establish the
-- one-directional equivalence, the following lemma is needed, which
-- has the flavour of a progress lemma for big-step semantics:
-- (cf. the proof of Lemma 36 in "Coinductive big-step operational
-- semantics" by X. Leroy and H. Grall)
coBigStepProgress : (e1 : Term [] t) -> (e2 : Term [] t) ->
                    CoBigStep e1 e2 ->
                    Either (Value e1) (b : Term [] t ** (Step e1 b, CoBigStep b e2))
coBigStepProgress (TVar _) e2 cbst impossible
--
coBigStepProgress (TAbs _) e2 cbst = Left VAbs
--
coBigStepProgress (TApp x y) (TApp x y) (CoBStValue v) impossible
coBigStepProgress (TApp x y) e2 (CoBStApp {e=e2} {e1'=e1'} {e2'=e2'} cbst1 cbst2 cbst3) =
  case coBigStepProgress x (TAbs e1') cbst1 of
       Left v => case v of
                      VAbs => case cbst1 of
                                   (CoBStValue {e=(TAbs e)} v') => case coBigStepProgress y e2' cbst2 of
                                                                        Left v'' => let eq     = coBigStepValueIrreducible cbst2 v''
                                                                                cbst3' = replace {P = \z => CoBigStep (subst z First e) e2} (sym eq) cbst3
                                                                                in Right (_ ** (StBeta v'', cbst3'))
                                                                        Right (b ** (st, cbst)) => let cbst' = CoBStApp (CoBStValue v) cbst cbst3
                                                                                in Right (_ ** (StApp2 VAbs st, cbst'))
       Right (b ** (st, cbst)) => let st'   = StApp1 st
                                      cbst' = CoBStApp cbst cbst2 cbst3
                                  in Right (_ ** (st', cbst'))
--
coBigStepProgress (TFix x) (TFix x) (CoBStValue v) impossible
coBigStepProgress (TFix x) e2 (CoBStFix {e'=e'} cbst1 cbst2) =
  case coBigStepProgress x (TAbs e') cbst1 of
       Left v => case v of
                      VAbs => case cbst1 of
                                   (CoBStValue {e=(TAbs e)} v) => Right (_ ** (StFixBeta, cbst2))
       Right (b ** (st, cbst)) => let st'   = StFix st
                                      cbst' = CoBStFix cbst cbst2
                                  in Right (_ ** (st', cbst'))
--
coBigStepProgress TZero e2 _ = Left VZero
--
coBigStepProgress (TSucc x) (TVar y) cbst impossible
coBigStepProgress (TSucc _) (TApp _ _) (CoBStValue _) impossible
coBigStepProgress (TSucc _) (TApp _ _) (CoBStApp _ _ _) impossible
coBigStepProgress (TSucc _) (TApp _ _) (CoBStFix _ _) impossible
coBigStepProgress (TSucc _) (TApp _ _) (CoBStSucc _) impossible
coBigStepProgress (TSucc _) (TApp _ _) (CoBStPredZero _) impossible
coBigStepProgress (TSucc _) (TApp _ _) (CoBStPredSucc _) impossible
coBigStepProgress (TSucc _) (TApp _ _) (CoBStIfzZero _ _) impossible
coBigStepProgress (TSucc _) (TApp _ _) (CoBStIfzSucc _ _) impossible
coBigStepProgress (TSucc _) (TFix _) (CoBStValue _) impossible
coBigStepProgress (TSucc _) (TFix _) (CoBStApp _ _ _) impossible
coBigStepProgress (TSucc _) (TFix _) (CoBStFix _ _) impossible
coBigStepProgress (TSucc _) (TFix _) (CoBStSucc _) impossible
coBigStepProgress (TSucc _) (TFix _) (CoBStPredZero _) impossible
coBigStepProgress (TSucc _) (TFix _) (CoBStPredSucc _) impossible
coBigStepProgress (TSucc _) (TFix _) (CoBStIfzZero _ _) impossible
coBigStepProgress (TSucc _) (TFix _) (CoBStIfzSucc _ _) impossible
coBigStepProgress (TSucc _) TZero (CoBStValue _) impossible
coBigStepProgress (TSucc _) TZero (CoBStApp _ _ _) impossible
coBigStepProgress (TSucc _) TZero (CoBStFix _ _) impossible
coBigStepProgress (TSucc _) TZero (CoBStSucc _) impossible
coBigStepProgress (TSucc _) TZero (CoBStPredZero _) impossible
coBigStepProgress (TSucc _) TZero (CoBStPredSucc _) impossible
coBigStepProgress (TSucc _) TZero (CoBStIfzZero _ _) impossible
coBigStepProgress (TSucc _) TZero (CoBStIfzSucc _ _) impossible
coBigStepProgress (TSucc _) (TPred _) (CoBStValue _) impossible
coBigStepProgress (TSucc _) (TPred _) (CoBStApp _ _ _) impossible
coBigStepProgress (TSucc _) (TPred _) (CoBStFix _ _) impossible
coBigStepProgress (TSucc _) (TPred _) (CoBStSucc _) impossible
coBigStepProgress (TSucc _) (TPred _) (CoBStPredZero _) impossible
coBigStepProgress (TSucc _) (TPred _) (CoBStPredSucc _) impossible
coBigStepProgress (TSucc _) (TPred _) (CoBStIfzZero _ _) impossible
coBigStepProgress (TSucc _) (TPred _) (CoBStIfzSucc _ _) impossible
coBigStepProgress (TSucc _) (TIfz _ _ _) (CoBStValue _) impossible
coBigStepProgress (TSucc _) (TIfz _ _ _) (CoBStApp _ _ _) impossible
coBigStepProgress (TSucc _) (TIfz _ _ _) (CoBStFix _ _) impossible
coBigStepProgress (TSucc _) (TIfz _ _ _) (CoBStSucc _) impossible
coBigStepProgress (TSucc _) (TIfz _ _ _) (CoBStPredZero _) impossible
coBigStepProgress (TSucc _) (TIfz _ _ _) (CoBStPredSucc _) impossible
coBigStepProgress (TSucc _) (TIfz _ _ _) (CoBStIfzZero _ _) impossible
coBigStepProgress (TSucc _) (TIfz _ _ _) (CoBStIfzSucc _ _) impossible
coBigStepProgress (TSucc y) (TSucc y) (CoBStValue v) = Left v
coBigStepProgress (TSucc x) (TSucc y) (CoBStSucc cbst) =
  case coBigStepProgress x y cbst of
       Left v => Left (VSucc v)
       Right (b ** (st, cbst)) => let st'   = StSucc st
                                      cbst' = CoBStSucc cbst
                                  in Right (_ ** (st', cbst'))
--
coBigStepProgress (TPred x) (TPred x) (CoBStValue v) impossible
coBigStepProgress (TPred x) TZero (CoBStPredZero cbst) =
  case coBigStepProgress x TZero cbst of
       Left v => case v of
                      VZero    => Right (_ ** (StPredZero, CoBStValue VZero))
                      VSucc v' => case coBigStepValueIrreducible cbst v of
                                       Refl impossible
       Right (b ** (st, cbst)) => let st'   = StPred st
                                      cbst' = CoBStPredZero cbst
                                  in Right (_ ** (st', cbst'))
coBigStepProgress (TPred x) e2 (CoBStPredSucc cbst) =
  case coBigStepProgress x (TSucc e2) cbst of
       Left v => case v of
                      VZero => case coBigStepValueIrreducible cbst v of
                                    Refl impossible
                      VSucc v' => case coBigStepValueIrreducible cbst v of
                                       Refl => Right (_ ** (StPredSucc v', CoBStValue v'))
       Right (b ** (st, cbst)) => let st' = StPred st
                                  in Right (_ ** (st', CoBStPredSucc cbst))
--
coBigStepProgress (TIfz x y z) (TIfz x y z) (CoBStValue v) impossible
coBigStepProgress (TIfz x y z) e2 (CoBStIfzZero cbst1 cbst2) =
  case coBigStepProgress x TZero cbst1 of
       Left v => case coBigStepValueIrreducible cbst1 v of
                      Refl => Right (_ ** (StIfzZero, cbst2))
       Right (b ** (st, cbst)) => let st'   = StIfz st
                                      cbst' = CoBStIfzZero cbst cbst2
                                  in Right (_ ** (st', cbst'))
coBigStepProgress (TIfz x y z) e2 (CoBStIfzSucc cbst1 cbst2) =
  case coBigStepProgress x (TSucc _) cbst1 of
       Left v => case coBigStepValueIrreducible cbst1 v of
                      Refl => case v of
                                   VSucc v' => Right (_ ** (StIfzSucc v', cbst2))
       Right (b ** (st, cbst)) => let st'   = StIfz st
                                      cbst' = CoBStIfzSucc cbst cbst2
                                  in Right (_ **(st', cbst'))

-- With the previous lemma, one can finally prove the
-- implication 'CoBigStep' => 'CoTransStep':
-- (i.e. Lemma 36 in "Coinductive big-step operational semantics"
-- by X. Leroy and H. Grall)
coBigStepToTransStep : (e1 : Term [] t) -> (e2 : Term [] t) ->
                       CoBigStep e1 e2 -> CoTransStep e1 e2
coBigStepToTransStep e1 e2 cbst =
  case coBigStepProgress e1 e2 cbst of
       Left v => case coBigStepValueIrreducible cbst v of
                      Refl => CoTStRefl e1
       Right (b ** (st, cbst)) => CoTStTrans st $ coBigStepToTransStep b e2 cbst

-- End: CO-BIG-STEP => CO-TRANSSTEP
-----------------------------------

---------------------------------------
-- Begin: CO-TRANSSTEP =/=> CO-BIG-STEP

-- The following application serves to show that the relations
-- 'CoTransStep' and 'CoBigStep' are not equivalent:
-- (This example follows Lemma 36 in "Coinductive big-step
-- operational semantics" by X. Leroy and H. Grall.)
appOmega : Term [] TyNat
appOmega = TApp (TAbs {s=TyNat} TZero) (Subst.omega {t=TyNat})

-- Under 'CoTransStep' the term 'appOmega' evaluates to anything:
appOmegaCoTransStepAny : (e : Term [] TyNat) -> CoTransStep Equivalence.appOmega e
appOmegaCoTransStepAny e = let st = StApp2 {v=(TAbs TZero)} VAbs StFixBeta
                           in CoTStTrans st (appOmegaCoTransStepAny e)

-- The following re-states a result from 'Determinism.idr'
-- (in order to avoid importing 'Determinism.idr', which
-- would lead to a cycle of imports):
coBigStepOmegaAny : CoBigStep Subst.omega e
coBigStepOmegaAny = CoBStFix (CoBStValue VAbs) Equivalence.coBigStepOmegaAny

appOmegaCoBigStepZero : CoBigStep Equivalence.appOmega TZero
appOmegaCoBigStepZero = let cbst1  = CoBStValue {e=(TAbs TZero)} VAbs
                            cbst2  = Equivalence.coBigStepOmegaAny {e=Subst.omega}
                            cbst3  = CoBStValue VZero
                        in CoBStApp cbst1 cbst2 cbst3

-- Under 'CoBigStep' the term 'appOmega' only evaluates
-- to 'TZero' (and to nothing else):
appOmegaCoBigStepOnlyZero : (e : Term [] TyNat) ->
                            CoBigStep Equivalence.appOmega e ->
                            e = TZero
appOmegaCoBigStepOnlyZero _ (CoBStValue VZero)     impossible
appOmegaCoBigStepOnlyZero _ (CoBStValue (VSucc _)) impossible
appOmegaCoBigStepOnlyZero _ (CoBStValue VAbs)      impossible
appOmegaCoBigStepOnlyZero e (CoBStApp cbst1 cbst2 cbst3) =
  case coBigStepValueIrreducible cbst1 VAbs of
       Refl => sym $ coBigStepValueIrreducible cbst3 VZero

-- End: CO-TRANSSTEP =/=> CO-BIG-STEP
-------------------------------------


module Bautzen.ZoC

import Bautzen.GameUnit
import Bautzen.Terrain

import public Data.List
import public Data.List.Elem
import public Decidable.Equality
import Data.Nat
import Data.Vect

-- section 3
-- zones of control

public export
data ZoC : Type where
  InZoC : (side : Side) -> ZoC
  Free : ZoC

public export
Eq ZoC where
  Free == Free = True
  (InZoC s) == (InZoC s') = s == s'
  _ == _ = False

||| Test if given position for given `side` is in the ZoC of the unit.
public export
inZocOf : (pos : Pos) -> (side : Side) -> (GameUnit, Pos) -> Bool
inZocOf pos curSide (unit, location) =
  if curSide == side (nation unit)
  then False
  else case pos `isElem` neighbours location of
    (Yes prf) => True
    (No contra) => False

||| Is the given `Pos`ition in an enemy ZoC?
||| This assumes the current `side` is playing and checking ZoCs
public export
inZoC : Side -> List (GameUnit, Pos) -> Pos -> ZoC
inZoC curSide units pos =
  case find (inZocOf pos curSide) units of
    Nothing => Free
    (Just (unit, _)) => InZoC (side $ nation unit)

-- ZoC tests

-- inZoCTrue : inZocOf (hex 3 3) Axis (Bautzen.GameUnit.p13_5dp, hex 3 4) = True
-- inZoCTrue = Refl

-- inZoCTrue2 : inZocOf (hex 4 3) Axis (Bautzen.GameUnit.p13_5dp, hex 3 4) = False
-- inZoCTrue2 = Refl

inZoCFalsePolish : inZocOf (hex 3 3) Allies (Bautzen.GameUnit.p13_5dp, hex 3 4) = False
inZoCFalsePolish = Refl


> module BoundedNat.Properties

> import Data.Fin
> import Control.Isomorphism
> import Syntax.PreorderReasoning

> import BoundedNat.BoundedNat
> import BoundedNat.Operations
> import Basic.Operations
> import Nat.LTProperties
> import Sigma.Sigma
> import Pairs.Operations
> import Sigma.Properties
> import Fin.Properties
> import Finite.Predicates
> import Unique.Predicates

> %default total
> %access public export
> %auto_implicits on

No natural number is smaller than zero

> implementation [UninhabitedLTBZ] Uninhabited (LTB Z) where
>   uninhabited (MkSigma n prf) = absurd prf

Basic properties

> |||
> toFinLemma0 : (n : Nat) -> (b : Nat) -> (prf : LT n b) ->
>               finToNat (toFin (MkSigma n prf)) = n
> toFinLemma0   n     Z             prf  = absurd prf
> toFinLemma0   Z    (S a) (LTESucc prf) = Refl
> toFinLemma0  (S m) (S a) (LTESucc prf) = let ih = toFinLemma0 m a prf
>                                          in rewrite ih in Refl
> %freeze toFinLemma0 -- frozen

> |||
> toFinLemma1 : (n : Nat) -> (b : Nat) -> (prf : LT n b) ->
>               finToNat (FS (toFin (MkSigma n prf))) = S n
> toFinLemma1 n b prf =
>     ( finToNat (FS (toFin (MkSigma n prf))) )
>   ={ Refl }=                             -- definition of |finToNat|
>     ( S (finToNat (toFin (MkSigma n prf)))  )
>   ={ cong (toFinLemma0 n b prf) }=       -- |toFinLemma0|, functionality of |S|
>     ( S n                              )
>   QED
> %freeze toFinLemma1 -- frozen

> |||
> toFinLemma2 : (n : Nat) -> (b : Nat) -> (prf : LT n b) ->
>               finToNatLemma (toFin (MkSigma n prf)) = prf
> toFinLemma2   n     Z     prf              = absurd prf
> toFinLemma2   Z    (S b) (LTESucc LTEZero) = Refl
> {-
> toFinLemma2  (S n) (S b) (LTESucc prf) =
>     ( finToNatLemma (toFin (S n ** LTESucc prf)) )
>   ={ Refl }=                                       -- definition of |toFin|
>     ( finToNatLemma (FS (toFin (n ** prf)))      )
>   ={ Refl }=                                       -- definition of |finToNatLemma|
>     ( LTESucc (finToNatLemma (toFin (n ** prf))) )
>   ={ depCong2' {alpha = Nat}
>                {P = \ n => LT n b}
>                {Q = \ n, prf => LT (S n) (S b)}
>                {a1 = finToNat (toFin (n ** prf))}
>                {a2 = n}
>                {Pa1 = finToNatLemma (toFin (n ** prf))}
>                {Pa2 = prf}
>                (\ n, prf => LTESucc prf)
>                (toFinLemma0 n b prf)
>                (toFinLemma2 n b prf) }=
>     ( LTESucc prf                                )
>   QED
> -}
> --{-
> toFinLemma2  (S n) (S b) (LTESucc prf) = trans s1 (trans s2 s3) where
>   s1 : finToNatLemma (toFin (MkSigma (S n) (LTESucc prf)))
>        =
>        finToNatLemma (FS (toFin (MkSigma n prf)))
>   s1 = Refl
>   s2 : finToNatLemma (FS (toFin (MkSigma n prf)))
>        =
>        LTESucc (finToNatLemma (toFin (MkSigma n prf)))
>   s2 = Refl
>   {-
>   sx : finToNatLemma (toFin (n ** prf))
>        =
>        prf
>   sx = toFinLemma2 n b prf
>   sy : LTESucc (finToNatLemma (toFin (n ** prf)))
>        =
>        LTESucc prf
>   sy = cong {a = finToNatLemma (toFin (n ** prf))} {b = prf} {f = LTESucc} sx
>   -}
>   s3 : LTESucc (finToNatLemma (toFin (MkSigma n prf)))
>        =
>        LTESucc prf
>   s3 = depCong2' {alpha = Nat}
>                  {P = \ n => LT n b}
>                  {Q = \ n, prf => LT (S n) (S b)}
>                  {a1 = finToNat (toFin (MkSigma n prf))}
>                  {a2 = n}
>                  {Pa1 = finToNatLemma (toFin (MkSigma n prf))}
>                  {Pa2 = prf}
>                  {f = \ n, prf => LTESucc prf}
>                  (toFinLemma0 n b prf)
>                  (toFinLemma2 n b prf)
> ---}
> %freeze toFinLemma2 -- frozen

> |||
> toFinLemma3 : (n : Nat) -> (b : Nat) -> (prf : LT n b) ->
>               finToNatLemma (FS (toFin (MkSigma n prf))) = LTESucc prf
> {-
> toFinLemma3 n b prf =
>     ( finToNatLemma (FS (toFin (n ** prf)))      )
>   ={ replace {a = Fin (S b)}
>              {x = FS (toFin (n ** prf))}
>              {y = toFin (S n ** LTESucc prf)}
>              {P = \ x => finToNatLemma (FS (toFin (n ** prf))) = finToNatLemma x}
>              Refl Refl }=
>     ( finToNatLemma (toFin (S n ** LTESucc prf)) )
>   ={ toFinLemma2 (S n) (S b) (LTESucc prf) }=
>     ( LTESucc prf                                )
> -}
> toFinLemma3 n b prf = trans s1 s2 where
>   s0 : FS (toFin (MkSigma n prf)) = toFin (MkSigma (S n) (LTESucc prf))
>   s0 = Refl
>   s1 : finToNatLemma (FS (toFin (MkSigma n prf)))
>        =
>        finToNatLemma (toFin (MkSigma (S n) (LTESucc prf)))
>   s1 = replace {a = Fin (S b)}
>                {x = FS (toFin (MkSigma n prf))}
>                {y = toFin (MkSigma (S n) (LTESucc prf))}
>                {P = \ x => finToNatLemma (FS (toFin (MkSigma n prf))) = finToNatLemma x}
>                s0 Refl
>   s2 : finToNatLemma (toFin (MkSigma (S n) (LTESucc prf)))
>        =
>        LTESucc prf
>   s2 = toFinLemma2 (S n) (S b) (LTESucc prf)
> %freeze toFinLemma3 -- frozen

> {-
> |||
> toFinLemma6 : (n : Nat) -> (b : Nat) -> (prf : LT n b) ->
>               toFin (S n ** LTESucc prf) = FS (toFin (n ** prf))
> -}

> ||| |toFin| is the left-inverse of |fromFin|
> toFinFromFinLemma : (k : Fin b) -> toFin (fromFin k) = k
> toFinFromFinLemma {b = Z} k = absurd k
> toFinFromFinLemma {b = S m} FZ = Refl
> toFinFromFinLemma {b = S m} (FS k) =
>   let ih = toFinFromFinLemma k in
>   rewrite ih in
>   Refl
> %freeze toFinFromFinLemma -- frozen

> using implementation UninhabitedLTBZ
>   ||| |fromFin| is the left-inverse of |toFin|
>   fromFinToFinLemma : (n : LTB b) -> fromFin (toFin n) = n
>   fromFinToFinLemma {b = Z}   k                                   = absurd k
>   fromFinToFinLemma {b = S m} (MkSigma   Z    (LTESucc LTEZero))  = Refl
>   fromFinToFinLemma {b = S m} (MkSigma (S n) (LTESucc prf))       = s6 where
>     s1 : fromFin (toFin (MkSigma (S n) (LTESucc prf)))
>          =
>          fromFin (FS (toFin (MkSigma n prf)))
>     s1 = Refl
>     s2 : fromFin (FS (toFin (MkSigma n prf)))
>          =
>          MkSigma (finToNat (FS (toFin (MkSigma n prf)))) (finToNatLemma (FS (toFin (MkSigma n prf))))
>     s2 = Refl
>     s3 : finToNat (FS (toFin (MkSigma n prf))) = S n
>     s3 = toFinLemma1 n m prf
>     s4 : finToNatLemma (FS (toFin (MkSigma n prf))) = LTESucc prf
>     s4 = toFinLemma3 n m prf
>     s5 : MkSigma {A = Nat} {P = \ i => LT i (S m)}
>          (finToNat (FS (toFin (MkSigma n prf))))
>          (finToNatLemma (FS (toFin (MkSigma n prf))))
>          =
>          MkSigma {A = Nat} {P = \ i => LT i (S m)} (S n) (LTESucc prf)
>     s5 = depCong2 {f = MkSigma {A = Nat} {P = \ i => LT i (S m)}} s3 s4
>     s6 : fromFin (toFin (MkSigma (S n) (LTESucc prf))) = MkSigma (S n) (LTESucc prf)
>     s6 = trans s1 (trans s2 s5)
>   %freeze fromFinToFinLemma

Finitness properties

> ||| Bounded |Nat|s are finite:
> finiteLTB : (b : Nat) -> Finite (LTB b)
> finiteLTB b = MkSigma b iso where
>   iso : Iso (LTB b) (Fin b)
>   iso = MkIso toFin fromFin toFinFromFinLemma fromFinToFinLemma
> %freeze finiteLTB -- frozen

> {-
> ||| Subtypes of bounded |Nat|s are finite:
> finiteSubLTB : (b : Nat) -> (P : LTB b -> Type) -> Dec1 P -> (uP : Unique1 P) -> Finite (SubType (LTB b) P uP)
> finiteSubLTB b P dP uP = finiteSubTypeLemma0 {A = LTB b} {P} (finiteLTB b) dP uP
> -}

Decidability properties

> ||| Equality of bounded |Nat|s is decidable
> decEqLTB : {b : Nat} -> (i : LTB b) -> (j : LTB b) -> Dec (i = j)
> decEqLTB {b} (MkSigma m p) (MkSigma n q) with (decEq m n)
>   | (Yes prf)   = Yes (sigmaEqLemma1 (MkSigma m p) (MkSigma n q) prf (uniqueLT))
>   | (No contra) = No (\ prf => contra (getWitnessPreservesEq prf))
> %freeze decEqLTB -- frozen

> implementation [DecEqLTB] DecEq (LTB b) where
>   decEq {b} i j = decEqLTB {b} i j

Show

> using (b : Nat)
>   implementation [ShowLTB] Show (LTB b) where
>     show (MkSigma i _) = show i


transport : (0 eq : a === b) -> a -> b
transport eq x = rewrite sym eq in x

nested : (0 _ : a === b) -> (0 _ : b === c) -> a === c
nested eq1 eq2 =
  rewrite eq1 in
    rewrite eq2 in
      let prf : c === c := Refl in
      prf


||| For Plain Merge we need to assert that all branches in a choice are the same.
module Sessions.Local.Same.All

import Decidable.Equality
import Data.List
import Data.List.Elem

import Data.List1

import Sessions.Meta
import Sessions.Local
import Sessions.Local.Same

%default total

namespace List
  public export
  data All : (c  : Branch    role local msg rs g)
          -> (cs : Branches' role local msg rs g)
          -> (ne : NonEmpty cs)
                -> Type
    where
      Base : (prf : Equal c d)
                 -> All c (d :: Nil) IsNonEmpty

      Extend : (prf   : Equal c d)
            -> (prfNE : NonEmpty rest)
            -> (later : All c     rest  prfNE)
                     -> All c (d::rest) IsNonEmpty

  notEmpty : NonEmpty [] -> Void
  notEmpty IsNonEmpty impossible

  nonEmpty : (xs : List a) -> Dec (NonEmpty xs)
  nonEmpty [] = No notEmpty
  nonEmpty (x :: xs) = Yes IsNonEmpty

  data Shape : (xs : List a) -> Type where
    IsCons : Shape (x::xs)
    IsNil  : Shape Nil

  shape : (xs : List a) -> Shape xs
  shape [] = IsNil
  shape (x :: xs) = IsCons

  notSameHead : (c = x -> Void)
             -> All c (x :: xs) IsNonEmpty -> Void
  notSameHead f (Base prf) = f prf
  notSameHead f (Extend prf prfNE later) = f prf

  notSameRest : (All x (y :: xs) IsNonEmpty -> Void)
              -> All x (x :: (y :: xs)) IsNonEmpty
              -> Void
  notSameRest f (Extend Refl IsNonEmpty later) = f later

  export
  allSame : DecEq role label msg
         => (c     : Branch    role label msg rs g)
         -> (cs    : Branches' role label msg rs g)
         -> (prfNE : NonEmpty cs)
                  -> Dec (All c cs prfNE)
  allSame c (x :: xs) IsNonEmpty with (same c x)
    allSame x (x :: xs) IsNonEmpty | (Yes Refl) with (shape xs)
      allSame x (x :: (y :: xs)) IsNonEmpty | (Yes Refl) | IsCons with (allSame x (y::xs) IsNonEmpty)
        allSame x (x :: (y :: xs)) IsNonEmpty | (Yes Refl) | IsCons | (Yes prf) = Yes (Extend Refl IsNonEmpty prf)
        allSame x (x :: (y :: xs)) IsNonEmpty | (Yes Refl) | IsCons | (No contra)
          = No (notSameRest contra)
      allSame x (x :: []) IsNonEmpty | (Yes Refl) | IsNil
        = Yes (Base Refl)

    allSame c (x :: xs) IsNonEmpty | (No contra)
      = No (notSameHead contra)

namespace List1
  public export
  data All : (cs : Branches role label msg rs g)
              -> Type
    where
      Yes : All c (c::cs) IsNonEmpty -> All (c ::: cs)

  notAllSame : (All h (h :: t) IsNonEmpty -> Void) -> All (h ::: t) -> Void
  notAllSame f (Yes x) = f x

  export
  allSame : DecEq role label msg
         => (cs : Branches role label msg rs g)
               -> Dec (All cs)
  allSame (head ::: tail) with (allSame head (head :: tail) IsNonEmpty)
    allSame (head ::: tail) | (Yes prf) = Yes (Yes prf)
    allSame (head ::: tail) | (No contra)
      = No (notAllSame contra)

-- [ EOF ]


import Data.Vect
import vect

data GameState : (guesses_remaining : Nat) -> (letters : Nat) -> Type where
  MkGameState : (word : String)
                -> (missing : Vect letters Char)
                -> GameState guesses_remaining letters

data Finished : Type where
  Lost : (game : GameState 0 (S letters)) -> Finished
  Won : (game : GameState (S guesses) 0) -> Finished

data ValidInput : List Char -> Type where
  Letter : (c : Char) -> ValidInput [c]

isValidNil : ValidInput [] -> Void
isValidNil (Letter _) impossible

isValidTwo : ValidInput (x :: (y :: xs)) -> Void
isValidTwo (Letter _) impossible

isValidInput : (cs : List Char) -> Dec (ValidInput cs)
isValidInput [] = No isValidNil
isValidInput (x :: []) = Yes (Letter x)
isValidInput (x :: (y :: xs)) = No isValidTwo

isValidString : (s : String) -> Dec (ValidInput (unpack s))
isValidString s = isValidInput (unpack s)

readGuess : IO (x ** ValidInput x)
readGuess = do
  putStr "Guess: "
  x <- getLine
  case isValidString (toUpper x) of
    Yes prf => pure (_ ** prf)
    No contra => do
      putStrLn "Invalid Guess"
      readGuess

processGuess : (letter : Char) ->
               GameState (S guesses) (S letters) ->
               Either (GameState guesses (S letters))
                      (GameState (S guesses) letters)
processGuess letter (MkGameState word missing)
  = case isElem letter missing of
         (Yes prf) => Right (MkGameState word (removeElem letter missing))
         (No contra) => Left (MkGameState word missing)

game : GameState (S guesses) (S letters) -> IO Finished
game {guesses} {letters} st = do
  (_ ** Letter letter) <- readGuess
  case processGuess letter st of
       Left l => do
         putStrLn "Wrong!"
         case guesses of
              Z => pure (Lost l)
              S k => game l
       Right r => do
         putStrLn "Right!"
         case letters of
              Z => pure (Won r)
              S k => game r

main : IO ()
main = do
  result <- game {guesses=2} (MkGameState "Test" ['T', 'E', 'S'])
  case result of
       Lost (MkGameState word missing) =>
         putStrLn ("You lose. The word was " ++ word)
       Won (MkGameState word missing) =>
         putStrLn ("You win! The word was " ++ word)


module Main

import Data.Vect

infixr 5 .+.

data Schema = SString | SInt | (.+.) Schema Schema

SchemaType : Schema -> Type
SchemaType SString = String
SchemaType SInt = Int
SchemaType (x .+. y) = (SchemaType x, SchemaType y)

record DataStore (size : Nat) where
  constructor MkData
  schema : Schema
  items : Vect size (SchemaType schema)

setSchema : DataStore 0 -> Schema -> DataStore 0
setSchema (MkData schema []) schema' = MkData schema' []

data Command : Schema -> Type where
     SetSchema : Schema -> Command schema
     Add : SchemaType schema -> Command schema
     Get : Integer -> Command schema
     Quit : Command schema


module Replica.Other.Validation

%default total

public export
data Validation : (err, a : Type) -> Type where
  Valid : (x : a) -> Validation err a
  Error : (e : err) -> Validation err a

export
Functor (Validation err) where
  map f (Valid x) = Valid $ f x
  map f (Error x) = Error x

export
(Semigroup err) => Applicative (Validation err) where
  pure = Valid
  (Valid f)  <*> (Valid x)  = Valid $ f x
  (Valid _)  <*> (Error e)  = Error e
  (Error e)  <*> (Valid x)  = Error e
  (Error e1) <*> (Error e2) = Error $ e1 <+> e2

export
(Monoid err) => Alternative (Validation err) where
  empty = Error neutral
  (<|>) (Valid x) y = Valid x
  (<|>) (Error e) (Valid y) = Valid y
  (<|>) (Error e) (Error r) = Error $ e <+> r

export
fromEither : Applicative f =>  Either err a -> Validation (f err) a
fromEither = either (Error . pure) Valid


%prefix_record_projections off

data T : Nat -> Type where
  MkT : (n : Nat) -> T n

record R where
  n : Nat
  x : T n


-- --------------------------------------------------------------- [ State.idr ]
-- Module      : Chapter.State
-- Description : Definitions from Chapter 12 of Edwin Brady's book,
--               "Type-Driven Development with Idris."
-- --------------------------------------------------------------------- [ EOH ]
module Chapter.State

-- NOTE: See 12.1.3
import public Control.Monad.State

-- NOTE: See 12.3.6
import Data.Primitives.Views

-- ----------------------------------------- [ 12.1 Working with Mutable State ]

||| Attach labels from `lbls` to elements of `vals`.
||| @ lbls A stream of labels.
||| @ vals A list of values.
export
labelWith : (lbls : Stream labelType) -> (vals : List a) -> List (labelType, a)
labelWith lbls [] = []
labelWith (lbl :: lbls) (val :: vals) = (lbl, val) :: labelWith lbls vals

-- ---------------------------------- [ 12.1.1 Running Example: Tree Traversal ]

public export
data Tree a = Empty
            | Node (Tree a) a (Tree a)

public export
testTree : Tree String
testTree = Node (Node (Node Empty "Jim" Empty) "Fred"
                      (Node Empty "Sheila" Empty)) "Alice"
                (Node Empty "Bob" (Node Empty "Eve" Empty))

export
flatten : Tree a -> List a
flatten Empty = []
flatten (Node left val right) = flatten left ++ val :: flatten right

-- -------------------------- [ 12.1.2 Representing Mutable State using a Pair ]

export
treeLabelWith : Stream labelType -> Tree a ->
                (Stream labelType, Tree (labelType, a))
treeLabelWith lbls Empty = (lbls, Empty)
treeLabelWith lbls (Node left val right)
  = let (this :: lblsLeft, leftLabelled) = treeLabelWith lbls left
        (lblsRight, rightLabelled) = treeLabelWith lblsLeft right in
        (lblsRight, Node leftLabelled (this, val) rightLabelled)

export
treeLabel : Tree a -> Tree (Integer, a)
treeLabel tree = snd (treeLabelWith [1..] tree)

-- ----------------- [ 12.1.3 State, a Type for Describing Stateful Operations ]

export
increase : Nat -> State Nat ()
increase inc = do current <- get
                  put (current + inc)

-- NOTE:
-- runState : StateT stateType Identity a -> stateType -> (a, stateType)
-- evalState : State stateType a -> stateType -> a
-- execState : State stateType a -> stateType -> stateType
-- get : MonadState stateType m => m stateType
-- put : MonadState stateType m => stateType -> m ()

-- ---------------------------------------- [ 12.1.4 Tree Traversal with State ]

namespace Stateful
  export
  treeLabelWith : Tree a -> State (Stream labelType) (Tree (labelType, a))
  treeLabelWith Empty = pure Empty
  treeLabelWith (Node left val right)
    = do leftLabelled <- treeLabelWith left
         -- Get the current stream of labels.
         (this :: rest) <- get
         -- Set the new stream of labels to be
         -- the tail of the current stream, rest.
         put rest
         rightLabelled <- treeLabelWith right
         pure (Node leftLabelled (this, val) rightLabelled)

  export
  treeLabel : Tree a -> Tree (Integer, a)
  treeLabel tree = evalState (treeLabelWith tree) [1..]

-- ----------------------------------------------------------- [ Listing 12.13 ]

export
addIfPositive : Integer -> State Integer Bool
addIfPositive val = do let positive = val > 0
                       when positive $ update (+ val)
                       pure positive
  where
    update = (get >>=) . (put .)

export
addPositives : List Integer -> State Integer Nat
addPositives vals = do added <- traverse addIfPositive vals
                       pure (length (filter id added))

-- ---------------------------------------------------- [ 12.3.2 Complex State ]

public export
record Score where
       constructor MkScore
       correct, attempted : Nat

public export
record GameState where
       constructor MkGameState
       score : Score
       difficulty : Int

public export
implementation Show GameState where
  show st = show (record { score->correct } st) ++ " / " ++
            show (record { score->attempted } st) ++ "\n" ++
            "Difficulty: " ++ show (difficulty st)

export
initState : GameState
initState = MkGameState (MkScore 0 0) 12

-- ------------------------------------- [ 12.3.1 The Arithmetic Quiz Revisted ]

public export
data Command : Type -> Type where
     PutStr : String -> Command ()
     GetLine : Command String

     GetRandom : Command Int

     GetGameState : Command GameState

     PutGameState : GameState -> Command ()

     Pure : ty -> Command ty
     Bind : Command a -> (a -> Command b) -> Command b

public export
data ConsoleIO : Type -> Type where
     Quit : a -> ConsoleIO a
     Do : Command a -> (a -> Inf (ConsoleIO b)) -> ConsoleIO b

namespace CommandDo

  public export
  (>>=) : Command a -> (a -> Command b) -> Command b
  (>>=) = Bind

namespace ConsoleDo

  public export
  (>>=) : Command a -> (a -> Inf (ConsoleIO b)) -> ConsoleIO b
  (>>=) =  Do

public export
data Fuel = Dry | More (Lazy Fuel)

public export
partial
forever : Fuel
forever = More forever

-- ----------------------------------------------- [ 12.3.6 Executing the Quiz ]

export
runCommand : Stream Int ->
             GameState ->
             Command a ->
             IO (a, Stream Int, GameState)
runCommand rnds state (PutStr x) = do putStr x
                                      pure ((), rnds, state)
runCommand rnds state GetLine    = do str <- getLine
                                      pure (str, rnds, state)

runCommand (val :: rnds) state GetRandom =
  pure (getRandom val (difficulty state), rnds, state)
  where
    getRandom : Int -> Int -> Int
    getRandom val max with (divides val max)
      getRandom val 0             | DivByZero = 1
      getRandom ((_ * _) + rem) _ | DivBy prf = abs rem + 1

runCommand rnds state GetGameState            = pure (state, rnds, state)
runCommand rnds state (PutGameState newState) = pure ((), rnds, newState)

runCommand rnds state (Pure val) = pure (val, rnds, state)
runCommand rnds state (Bind c f) =
  do (res, newRnds, newState) <- runCommand rnds state c
     runCommand newRnds newState (f res)

export
run : Fuel -> Stream Int -> GameState -> ConsoleIO a ->
      IO (Maybe a, Stream Int, GameState)
run fuel rnds state (Quit val) = do pure (Just val, rnds, state)
run (More fuel) rnds state (Do cmd f) =
  do (res, newRnds, newState) <- runCommand rnds state cmd
     run fuel newRnds newState (f res)
run Dry rnds state _ = pure (Nothing, rnds, state)

-- ------------------------------------- [ 12.3.3 Updating Record Field Values ]

export
setDifficulty : Int -> GameState -> GameState
setDifficulty newDiff = record { difficulty = newDiff}

export
addWrong : GameState -> GameState
addWrong = record { score->attempted $= (+1) }

export
addCorrect : GameState -> GameState
addCorrect = record { score->correct   $= (+1)
                    , score->attempted $= (+1)
                    }

-- -------------------------------------------- [ 12.3.5 Implementing the Quiz ]

-- Copied from 11.3.3
public export
data Input = Answer Int
           | QuitCmd

mutual
  export
  correct : ConsoleIO GameState
  correct = do PutStr "Correct!\n"
               st <- GetGameState
               PutGameState (addCorrect st)
               quiz
  export
  wrong : Int -> ConsoleIO GameState
  wrong ans = do PutStr $ "Wrong, the answer is " ++ show ans ++ "\n"
                 st <- GetGameState
                 PutGameState (addWrong st)
                 quiz
  export
  readInput : (prompt : String) -> Command Input
  readInput prompt = do PutStr prompt
                        answer <- GetLine
                        if toLower answer == "quit"
                           then Pure QuitCmd
                           else Pure (Answer (cast answer))
  export
  quiz : ConsoleIO GameState
  quiz = do x <- GetRandom
            y <- GetRandom
            st <- GetGameState
            PutStr $ show st ++ "\n"
            let solution = x * y
            QuitCmd <- readInput $ show x ++ " * " ++ show y ++ "? "
              | Answer answer => if solution == answer
                                    then correct
                                    else wrong solution
            Quit st

-- ----------------------------------------------------------- [ Listing 12.32 ]

export
randoms : Int -> Stream Int
randoms seed = let seed' = 1664525 * seed + 1013904223 in
                   (seed' `shiftR` 2) :: randoms seed'

-- --------------------------------------------------------------------- [ EOF ]


module TypeListToFunction

%default total

TypeListFun : List Type -> Type
TypeListFun [] = Unit
TypeListFun (x::xs) = x -> TypeListFun xs

typeListFun : (ts : List Type) -> TypeListFun ts
typeListFun [] = ()
typeListFun (_::xs) = \_ => typeListFun xs


module Control.HigherOrder

infixr 0 ~>
infixr 0 ~~>

||| Type of natural transformations between two functors.
public export
0
(~>) : (Type -> Type) -> (Type -> Type) -> Type
f ~> g = forall a. f a -> g a

||| As above, but with explicit 0-morphisms.
public export
0
(~~>) : (Type -> Type) -> (Type -> Type) -> (Type -> Type)
(f ~~> g) a = f a -> g a

||| Higher-order functor, i.e. a functor
||| in the category of functors and natural transformations.
public export
interface HFunctor h where
  hmap : (Functor f, Functor g)
      =>   f ~>   g
      -> h f ~> h g

infixr 8 :+:

||| Higher-order disjoint union.
||| Effects are composed via this datatype.
public export
data (:+:) : (sig1 : (Type -> Type) -> (Type -> Type))
          -> (sig2 : (Type -> Type) -> (Type -> Type))
          -> (m : Type -> Type)
          -> (a : Type)
          -> Type where
  Inl : sig1 m a -> (:+:) sig1 sig2 m a
  Inr : sig2 m a -> (:+:) sig1 sig2 m a

public export
HFunctor sig1 => HFunctor sig2 => HFunctor (sig1 :+: sig2) where
  hmap t (Inl op) = Inl (hmap t op)
  hmap t (Inr op) = Inr (hmap t op)

||| Higher order projections.
||| Prj forms a category.
public export
interface Prj (0 sup : (Type -> Type) -> (Type -> Type))
              (0 sub : (Type -> Type) -> (Type -> Type)) | sub where
  constructor MkPrj
  prj : sup m a -> sub m a

||| Higher order injections.
||| Inj forms a category.
public export
interface Inj (0 sub : (Type -> Type) -> (Type -> Type))
              (0 sup : (Type -> Type) -> (Type -> Type)) | sub where
  constructor MkInj
  inj : sub m a -> sup m a

export
Prj sub' sub => Inj sub sup => Inj sub' sup where
  inj = inj . prj {sup = sub', sub}

namespace Inj
  ||| Identity injection.
  ||| Example: `a :+: b ↦ a :+: b`
  public export
  [S] Inj sig sig where
     inj = id

  ||| Inject to a Sum from the left.
  ||| Example: `a ↦ a :+: b`
  public export
  [L] Inj sig1 (sig1 :+: sig2) where
    inj = Inl

  ||| Inject to a Sum from the right.
  ||| Example: `b ↦ a :+: b`
  public export
  [R] Inj sig2 (sig1 :+: sig2) where
    inj = Inr

  ||| Composition of injections.
  ||| Example: `b ↦ (a :+: b) :+: c`
  public export
  [Trans] (inner : Inj siga sigb) => (outer : Inj sigb sigc) => Inj siga sigc where
    inj = inj {sub = sigb, sup = sigc}
        . inj {sub = siga, sup = sigb}

  ||| Same as `Trans`, but the two arguments are explicit.
  public export
  T : (inner : Inj siga sigb) -> (outer : Inj sigb sigc) -> Inj siga sigc
  T inner outer = Trans @{inner} @{outer}

||| State-preserving transformation of
||| a computation in one monad into a computation
||| in another monad, whose value is annotated with the final state.
||| Handler is a natural transformation.
public export
0
Handler : (Type -> Type)
       -> (Type -> Type)
       -> (Type -> Type)
       -> Type
Handler s m n = s . m ~> n . s

||| Handler with explicit 0-morphism.
public export
0
HandlerX : (Type -> Type)
        -> (Type -> Type)
        -> (Type -> Type)
        -> (Type -> Type)
HandlerX s m n = s . m ~~> n . s

public export
interface HFunctor sig => Syntax sig where
  ||| Extend the continuation.
  emap : forall m. (m a -> m b) -> (sig m a -> sig m b)
  ||| Generically thread a handler through a higher-order
  ||| signature.
  weave : (m1 : Monad m) => (m2 : Monad n) => (fs : Functor s)
       => s ()
       -> Handler s m n
       -> (sig m a -> sig n (s a))

public export
Syntax sig1 => Syntax sig2 => Syntax (sig1 :+: sig2) where
  emap f (Inl op) = Inl (emap f op)
  emap f (Inr op) = Inr (emap f op)

  weave s hdl (Inl op) = Inl (weave s hdl op)
  weave s hdl (Inr op) = Inr (weave s hdl op)

||| Lift a first-order functor to a second-order one.
public export
data Lift : (sig : (Type -> Type))
         -> ((Type -> Type) -> (Type -> Type)) where
  MkLift : sig (m a) -> Lift sig m a

public export
unlift : Lift sig m a -> sig (m a)
unlift (MkLift x) = x

||| Alias for use as an effect.
public export
LiftE : (sig : Type -> Type) -> (Type -> Type) -> (Type -> Type)
LiftE = Lift

public export
Functor sig => HFunctor (Lift sig) where
  hmap t (MkLift op) = MkLift (map t op)

public export
Functor sig => Syntax (Lift sig) where
  emap f (MkLift op) = MkLift (map f op)

  weave s hdl (MkLift op) = MkLift $
    map (\p => hdl (map (const p) s)) op

infixr 1 ~<~

-- hdl1 : ctxt1 . m ~> n . ctxt1
-- hdl2 : ctxt2 . l ~> m . ctxt2
-- ?    : (ctxt1 . ctxt2) . l ~> n . (ctxt1 . ctxt2)
--
--  (ctxt1 . ctxt2) . l ===
--  ctxt1 . (ctxt2 . l) ==>
--  ctxt1 . (m . ctxt2) ===
--  (ctxt1 . m) . ctxt2 ==>
--  (n . ctxt1) . ctxt2 ===
--  n . (ctxt1 . ctxt2)
||| Fuse two handlers.
public export
(~<~) : (f : Functor n)
     => (g : Functor ctx1)
     => (forall q. HandlerX ctx1 m n q)
     -> (forall t. HandlerX ctx2 l m t)
     -> (forall p. HandlerX (ctx1 . ctx2) l n p)
hdl1 ~<~ hdl2 = hdl1 . map hdl2


module Regex.Type

import Pruviloj.Core
import Pruviloj.Derive.DecEq

infixl 7 :.:
infixl 6 :|:
infixl 6 :&:

%default total

||| The type of regular expressions over a given token type.
public export
data Regex : Type where
  ||| The regular expression matching nothing
  Ø     : Regex
  ||| The regular expression matching an empty string
  Ɛ     : Regex
  ||| The regular expression matching a single token
  Tok   : Char -> Regex
  ||| Kleene star
  Star  : Regex -> Regex
  ||| Union of two regular expressions
  (:|:) : Regex -> Regex -> Regex
  ||| Complement of regular expressions
  Comp  : Regex -> Regex
  ||| Intersection of two regular expressions
  (:&:) : Regex -> Regex -> Regex
  ||| Sequence one regular expression after another
  (:.:) : Regex -> Regex -> Regex

||| Decidable equality on regular expressions
public export
regexDecEq : (r : Regex) -> (s : Regex) -> Dec (r = s)
%runElab (deriveDecEq `{regexDecEq})

implementation DecEq Regex where
  decEq a b = regexDecEq a b

-- implementation Functor Regex where
--   map f Ø         = Ø
--   map f Ɛ         = Ɛ
--   map f (Tok t)   = Tok (f t)
--   map f (Comp r)  = Comp (map f r)
--   map f (Star r)  = Star (map f r)
--   map f (r :|: s) = (map f r) :|: (map f s)
--   map f (r :&: s) = (map f r) :&: (map f s)
--   map f (r :.: s) = (map f r) :.: (map f s)


import Data.Primitives.Views
import System

quiz : Stream Int -> (score : Nat) -> IO ()
quiz (num1 :: num2 :: nums) score
   = do putStrLn ("Score so far: " ++ show score)
        putStr (show num1 ++ " * " ++ show num2 ++ "? ")
        answer <- getLine
        if cast answer == num1 * num2
           then do putStrLn "Correct!"
                   quiz nums (score + 1)
           else do putStrLn ("Wrong, the answer is " ++ show (num1 * num2))
                   quiz nums score

randoms : Int -> Stream Int
randoms seed = let seed' = 1664525 * seed + 1013904223 in
                   (seed' `shiftR` 2) :: randoms seed'

arithInputs : Int -> Stream Int
arithInputs seed = map bound (randoms seed)
  where
    bound : Int -> Int
    bound x with (divides x 12)
      bound ((12 * div) + rem) | (DivBy div rem prf) = rem + 1

main : IO ()
main = do seed <- time
          quiz (arithInputs (fromInteger seed)) 0


module Uninh

data MyElem : a -> List a -> Type where
  MyHere : MyElem x (x :: xs)
  MyThere : (later : MyElem x xs) -> MyElem x (y :: xs)

noIndent : (MyElem a []) -> Void
noIndent c = ?noIndent_rhs

Uninhabited (MyElem a []) where
  uninhabited c = ?uninhabited_rhs


import Data.Vect

{- 1 -}

Matrix : Nat -> Nat -> Type
Matrix n m = Vect n (Vect m Double)

testMatrix : Matrix 2 3
testMatrix = [[0, 0, 0], [0, 0, 0]]


module STLCInterp

data HasType : List a -> a -> Type where
  VZ : HasType (t :: env) t
  VS : HasType env t -> HasType (_ :: env) t

data Expr : List Type -> Type -> Type where
  Val : Int -> Expr env Int
  Var : HasType env t -> Expr env t
  Lam : Expr (a :: env) b -> Expr env (a -> b)
  App : Expr env (a -> b) -> Expr env a -> Expr env b

interpEnv : List Type -> Type
interpEnv [] = ()
interpEnv (x :: xs) = (x, interpEnv xs)

lookup : HasType env t -> interpEnv env -> t
lookup VZ (t, _) = t
lookup (VS x) (_, ts) = lookup x ts

eval : interpEnv env -> %static Expr env t -> t
eval env (Val x) = x
eval env (Var x) = lookup x env
eval env (Lam body) = \x => eval (x, env) body
eval env (App f x) = (eval env f) (eval env x)

example : Expr [] Int
example = App (Lam (Var VZ)) (Val 42)

test : Int
test = eval () example


import Data.Vect

fourInts : Vect 4 Int
fourInts = [0,1,2,3]

||| The sum of both 4D vectors is an 8D vector
eightInts : Vect 8 Int
eightInts = fourInts ++ fourInts

total allLengths : Vect len String -> Vect len Nat
allLengths [] = []
allLengths (word :: words) = length word :: allLengths words

badLengthWithList : List String -> List Nat
badLengthWithList xs = []

badLengthWithVect : Vect n String -> Vect n Nat
badLengthWithVect xs = ?replace_with_empty_list_for_type_checking_error

anotherLengths : Vect length String -> Vect length Nat
anotherLengths [] = ?anotherLengths_rhs_1
anotherLengths (x :: xs) = ?anotherLengths_rhs_2


idF : a -> a
idF = id

extensionality : (f : a -> b) -> (g : a -> b) -> ((x : a) -> f x = g x) -> f = g
extensionality f g = believe_me

leftIdPoint : (f : a -> b) -> (x : a) -> idF (f x) = f x
leftIdPoint f x = Refl

leftId : (f : a -> b) -> (idF . f = f)
leftId f = ?hole