module NotStructurallyRecursive where
open import Data.Nat
open import NotStructurallyRecursive.Lemmas
open import Relation.Binary.PropositionalEquality
data Expr : Set where
val : ℕ -> Expr
_⊕_ : Expr -> Expr -> Expr
data Cont : Set where
STOP : Cont
ADD : ℕ -> Cont -> Cont
EVAL : Expr -> Cont -> Cont
sizeE : Expr -> ℕ
sizeE (val n) = 1
sizeE (e₁ ⊕ e₂) = 3 + sizeE e₁ + sizeE e₂
sizeC : Cont -> ℕ
sizeC STOP = 0
sizeC (ADD n c) = 1 + sizeC c
sizeC (EVAL e c) = 2 + sizeE e + sizeC c
mutual
eval : forall (e : Expr) (c : Cont) s -> s ≡ sizeE e + sizeC c -> ℕ
eval (val n) c zero ()
eval (val n) c (suc s) eq = exec c n s (cong pred eq)
eval (e₁ ⊕ e₂) c zero ()
eval (e₁ ⊕ e₂) c (suc s) eq = eval e₁ (EVAL e₂ c) s lem
where lem = lemma₁ (sizeE e₁) (sizeE e₂) (sizeC c) eq
exec : forall (c : Cont) (n : ℕ) s -> s ≡ sizeC c -> ℕ
exec STOP n _ _ = n
exec (ADD m c₁) n zero ()
exec (ADD m c₁) n (suc s) eq = exec c₁ (m + n) s (cong pred eq)
exec (EVAL e₁ c₂) n zero ()
exec (EVAL e₁ c₂) n (suc s) eq = eval e₁ (ADD n c₂) s lem
where lem = lemma₂ (sizeE e₁) (sizeC c₂) eq
run : Expr -> ℕ
run e = eval e STOP _ refl