open import Prelude
module Proof-by-reflection
{A : Set}
(identity : A)
(_∙_ : A → A → A)
(left-identity : ∀ x → (identity ∙ x) ≡ x)
(right-identity : ∀ x → (x ∙ identity) ≡ x)
(assoc : ∀ x y z → (x ∙ (y ∙ z)) ≡ ((x ∙ y) ∙ z))
(x y : A)
where
data Expr (n : ℕ) : Set where
var : Fin n → Expr n
id : Expr n
_⊕_ : Expr n → Expr n → Expr n
Env : ℕ → Set
Env n = Vec A n
⟦_⟧ : ∀ {n} → Expr n → Env n → A
⟦ var x ⟧ ρ = lookup x ρ
⟦ id ⟧ ρ = identity
⟦ e₁ ⊕ e₂ ⟧ ρ = ⟦ e₁ ⟧ ρ ∙ ⟦ e₂ ⟧ ρ
e₁ : Expr 2
e₁ = (var zero ⊕ id) ⊕ var (suc zero)
e₂ : Expr 2
e₂ = id ⊕ (var zero ⊕ (var (suc zero) ⊕ id))
ρ : Vec A 2
ρ = x ∷ y ∷ []
ex₁ = ⟦ e₁ ⟧ ρ
Normal : ℕ → Set
Normal n = List (Fin n)
⟦_⟧′ : ∀ {n} → Normal n → Env n → A
⟦ [] ⟧′ ρ = identity
⟦ x ∷ nf ⟧′ ρ = lookup x ρ ∙ ⟦ nf ⟧′ ρ
normalise : ∀ {n} → Expr n → Normal n
normalise (var x) = x ∷ []
normalise id = []
normalise (e₁ ⊕ e₂) = normalise e₁ ++ normalise e₂
homomorphic : ∀ {n} (nf₁ nf₂ : Normal n) (ρ : Env n) →
⟦ nf₁ ++ nf₂ ⟧′ ρ ≡ (⟦ nf₁ ⟧′ ρ ∙ ⟦ nf₂ ⟧′ ρ)
homomorphic [] nf₂ ρ = sym (left-identity (⟦ nf₂ ⟧′ ρ))
homomorphic (x ∷ nf₁) nf₂ ρ =
trans (cong (λ y → lookup x ρ ∙ y) (homomorphic nf₁ nf₂ ρ))
(assoc (lookup x ρ) (⟦ nf₁ ⟧′ ρ) (⟦ nf₂ ⟧′ ρ))
normalise-correct :
∀ {n} (e : Expr n) (ρ : Env n) → ⟦ normalise e ⟧′ ρ ≡ ⟦ e ⟧ ρ
normalise-correct (var x) ρ = right-identity (lookup x ρ)
normalise-correct id ρ = refl
normalise-correct (e₁ ⊕ e₂) ρ =
trans (homomorphic (normalise e₁) (normalise e₂) ρ)
(cong₂ _∙_ (normalise-correct e₁ ρ) (normalise-correct e₂ ρ))
normalisation-theorem :
∀ {n} (e₁ e₂ : Expr n) (ρ : Env n) →
⟦ normalise e₁ ⟧′ ρ ≡ ⟦ normalise e₂ ⟧′ ρ →
⟦ e₁ ⟧ ρ ≡ ⟦ e₂ ⟧ ρ
normalisation-theorem e₁ e₂ ρ eq =
trans (sym (normalise-correct e₁ ρ)) (
trans eq
(normalise-correct e₂ ρ))
ex₂ = normalisation-theorem e₁ e₂ ρ refl
infix 5 _≟_
_≟_ : ∀ {n} (nf₁ nf₂ : Normal n) → Maybe (nf₁ ≡ nf₂)
[] ≟ [] = just refl
(x₁ ∷ nf₁) ≟ (x₂ ∷ nf₂) = cong₂ _∷_ <$> x₁ ≟-Fin x₂ ⊛ nf₁ ≟ nf₂
_ ≟ _ = nothing
prove : ∀ {n} (e₁ e₂ : Expr n) → Maybe (∀ ρ → ⟦ e₁ ⟧ ρ ≡ ⟦ e₂ ⟧ ρ)
prove e₁ e₂ =
(λ eq ρ →
normalisation-theorem e₁ e₂ ρ (cong (λ nf → ⟦ nf ⟧′ ρ) eq))
<$> normalise e₁ ≟ normalise e₂
ex₃ = prove e₁ e₂
ex₄ : (x ∙ identity) ∙ y ≡ identity ∙ (x ∙ (y ∙ identity))
ex₄ = fromJust (prove e₁ e₂) ρ