{- 
  Mathematical Foundations of Programming (G54FOP)
  Nicolai Kraus
  Lecture 6, 15 Feb 2018
-}

module lec6FOP where

{- We import everything we have done last week.
   "open" means we can use all definitions directly -}
open import lec3FOP

{- Hint: middle mouse click or alt-.
   [press alt/meta, then .]
   jumps to the definition that the cursor is on -}

-- Reduce in one step
-- (these are the simplification rules)
data _→1_ : Expr → Expr → Set where
  izz : iz z →1 t
  izs : {e : Expr} → iz (s e) →1 f
  ift : {e₂ e₃ : Expr} → (if t then e₂ else e₃) →1 e₂
  iff : {e₂ e₃ : Expr} → (if f then e₂ else e₃) →1 e₃
  ps  : {e : Expr} → p (s e) →1 e
  pz  : p z →1 z

-- include structural rules
data _↝_ : Expr → Expr → Set where  -- type: \leadsto
  from→1   : {e₁ e₂ : Expr} → (e₁ →1 e₂) → (e₁ ↝ e₂)
  inside-s : {e₁ e₂ : Expr} → (e₁ ↝ e₂) → (s e₁ ↝ s e₂)
  inside-p : {e₁ e₂ : Expr} → (e₁ ↝ e₂) → (p e₁ ↝ p e₂)
  inside-iz : ∀ {e₁} {e₂} → (e₁ ↝ e₂) → (iz e₁ ↝ iz e₂)
  inside-ite1 : ∀ {e₁ e₁' e₂ e₃} → (e₁ ↝ e₁')
    → (if e₁ then e₂ else e₃) ↝ (if e₁' then e₂ else e₃)
  inside-ite2 : ∀ {e₁ e₂ e₂' e₃} → (e₂ ↝ e₂')
    → (if e₁ then e₂ else e₃) ↝ (if e₁ then e₂' else e₃)
  inside-ite3 : ∀ {e₁ e₂ e₃ e₃'} → (e₃ ↝ e₃')
    → (if e₁ then e₂ else e₃) ↝ (if e₁ then e₂ else e₃')

data _↝*_ : Expr → Expr → Set where
  start : ∀ {e} → e ↝* e
  step  : ∀ {e₁ e₂ e₃} → (e₁ ↝ e₂) → (e₂ ↝* e₃)
          → (e₁ ↝* e₃)

-- compose two reduction sequences
compose : {e₁ e₂ e₃ : Expr} → (e₁ ↝* e₂)
          → (e₂ ↝* e₃)
          → (e₁ ↝* e₃)
compose start s₂ = s₂
compose (step x s₁) s₂ = step x (compose s₁ s₂)

open import Data.Empty renaming (⊥ to ∅)  -- \emptyset

-- define what it means to be a normal form
is-normal : Expr → Set
is-normal e = (e₁ : Expr) → (e →1 e₁) → ∅

{- Exercises:
   1. (easy) Show that the expression "t" is
      in normal form. This means: fill the whole
      (replace the question mark) in
        t-nf : is-normal t
        t-nf = ?

   2. (medium) Show that, if "e" is a normal form,
      then so is "s e".

   3. (hard) Show that "is-normal" is a
      decidable predicate on Expr. 
      This means writing a function
      which takes an expression and tells us
      whether the expression is a normal form
      or not. The naive version would be
         Expr → Bool
      but we can do much better: we can take an
      expression "e" and either return a *proof*
      that "e" is a normal form, or return an
      example of how it can be reduced.
      Such an example would consist of an expression
      "reduct" and a proof of "e ↝ reduct"; we
      will learn later how this can be expressed,
      but a good way of implementing it is as follows:
-}

record can-red (e : Expr) : Set where
  field
    reduct  : Expr
    redstep : e ↝ reduct

{- Ex 3, continued: We can import Data.Sum to get the
   definition of ⊎ (type: \u+), a disjoint sum (it's
   Either in Haskell). Check out how ⊎ is defined in
   the library, it's really simple! -}

open import Data.Sum

{- Ex3, continued: Now, fill in the ? in the following
   function; probably, you will want more auxiliary
   lemma. Caveat: I have not done this myself. 
   
decide-nf : (e : Expr) → (is-normal e) ⊎ can-red e
decide-nf e = {!!}

-}