module Lambda.VirtualMachine where
open import Category.Monad
open import Category.Monad.Partiality as P
using (_⊥; never); open P._⊥
open import Coinduction
open import Data.Empty using (⊥-elim)
open import Data.Fin
open import Data.List
open import Data.Maybe
open import Data.Nat
open import Data.Product as Prod
open import Data.Star hiding (return)
open import Data.Vec using (Vec; []; _∷_; lookup)
open import Function
open import Relation.Binary.PropositionalEquality as PE using (_≡_)
open import Relation.Nullary
open RawMonad P.monad
open import Lambda.Syntax
private module C = Closure Tm
mutual
data Instr (n : ℕ) : Set where
Var : (x : Fin n) → Instr n
Con : (i : ℕ) → Instr n
Clos : (c : Code (suc n)) → Instr n
App : Instr n
Ret : Instr n
Code : ℕ → Set
Code n = List (Instr n)
open Closure Code
⟦_⟧ : ∀ {n} → Tm n → Code n → Code n
⟦ con i ⟧ c = Con i ∷ c
⟦ var x ⟧ c = Var x ∷ c
⟦ ƛ t ⟧ c = Clos (⟦ t ⟧ [ Ret ]) ∷ c
⟦ t₁ · t₂ ⟧ c = ⟦ t₁ ⟧ (⟦ t₂ ⟧ (App ∷ c))
mutual
⟦_⟧ρ : ∀ {n} → C.Env n → Env n
⟦ [] ⟧ρ = []
⟦ v ∷ ρ ⟧ρ = ⟦ v ⟧v ∷ ⟦ ρ ⟧ρ
⟦_⟧v : C.Value → Value
⟦ con i ⟧v = con i
⟦ ƛ t ρ ⟧v = ƛ (⟦ t ⟧ [ Ret ]) ⟦ ρ ⟧ρ
lookup-hom : ∀ {n} (x : Fin n) ρ → lookup x ⟦ ρ ⟧ρ ≡ ⟦ lookup x ρ ⟧v
lookup-hom zero (v ∷ ρ) = PE.refl
lookup-hom (suc x) (v ∷ ρ) = lookup-hom x ρ
data StackElement : Set where
val : (v : Value) → StackElement
ret : ∀ {n} (c : Code n) (ρ : Env n) → StackElement
Stack : Set
Stack = List StackElement
data State : Set where
⟨_,_,_⟩ : ∀ {n} (c : Code n) (s : Stack) (ρ : Env n) → State
module Relational where
infix 4 _⟶_
data _⟶_ : State → State → Set where
Var : ∀ {n} {x : Fin n} {c s ρ} →
⟨ Var x ∷ c , s , ρ ⟩ ⟶ ⟨ c , val (lookup x ρ) ∷ s , ρ ⟩
Con : ∀ {n i} {c : Code n} {s ρ} →
⟨ Con i ∷ c , s , ρ ⟩ ⟶ ⟨ c , val (con i) ∷ s , ρ ⟩
Clos : ∀ {n} {c : Code n} {c′ s ρ} →
⟨ Clos c′ ∷ c , s , ρ ⟩ ⟶ ⟨ c , val (ƛ c′ ρ) ∷ s , ρ ⟩
App : ∀ {n} {c : Code n} {v n′} {c′ : Code (suc n′)} {ρ′ s ρ} →
⟨ App ∷ c , val v ∷ val (ƛ c′ ρ′) ∷ s , ρ ⟩ ⟶ ⟨ c′ , ret c ρ ∷ s , v ∷ ρ′ ⟩
Ret : ∀ {n} {c : Code n} {v n′} {c′ : Code n′} {ρ′ s ρ} →
⟨ Ret ∷ c , val v ∷ ret c′ ρ′ ∷ s , ρ ⟩ ⟶ ⟨ c′ , val v ∷ s , ρ′ ⟩
Final : State → Set
Final s = ∄ λ s′ → s ⟶ s′
infix 4 _⇓_
data _⇓_ : State → Value → Set where
final : ∀ {v} → ⟨ [] , val v ∷ [] , [] ⟩ ⇓ v
⇓-final : ∀ {s v} → s ⇓ v → Final s
⇓-final final (_ , ())
Stuck : State → Set
Stuck s = Final s × ∄ (λ v → s ⇓ v)
infix 4 _⟶⋆_
_⟶⋆_ : State → State → Set
_⟶⋆_ = Star _⟶_
infixr 5 _◅_
infix 4 _⟶∞
data _⟶∞ : State → Set where
_◅_ : ∀ {s₁ s₂} (s₁⟶s₂ : s₁ ⟶ s₂) (s₂⟶∞ : ∞ (s₂ ⟶∞)) → s₁ ⟶∞
module InfiniteSequence where
infix 4 _⟶∞′
infixr 2 _⟶⟨_⟩′_ _⟶⋆⟨_⟩′_
infix 2 _⟶∞⟨_⟩
data _⟶∞′ : State → Set where
_⟶⟨_⟩′_ : ∀ s₁ {s₂} (s₁⟶s₂ : s₁ ⟶ s₂) (s₂⟶∞ : ∞ (s₂ ⟶∞′)) → s₁ ⟶∞′
_⟶⋆⟨_⟩′_ : ∀ s₁ {s₂} (s₁⟶⋆s₂ : s₁ ⟶⋆ s₂) (s₂⟶∞ : s₂ ⟶∞′) → s₁ ⟶∞′
_⟶∞⟨_⟩ : ∀ s (s⟶∞ : s ⟶∞′) → s ⟶∞′
sound : ∀ {s} → s ⟶∞′ → s ⟶∞
sound (s₁ ⟶⟨ s₁⟶s₂ ⟩′ s₂⟶∞) = s₁⟶s₂ ◅ ♯ (sound (♭ s₂⟶∞))
sound (s ⟶⋆⟨ ε ⟩′ s⟶∞) = sound s⟶∞
sound (s₁ ⟶⋆⟨ s₁⟶s₂ ◅ s₂⟶⋆s₃ ⟩′ s₃⟶∞) = s₁⟶s₂ ◅ ♯ (sound (_ ⟶⋆⟨ s₂⟶⋆s₃ ⟩′ s₃⟶∞))
sound (s ⟶∞⟨ s⟶∞ ⟩) = sound s⟶∞
complete : ∀ {s} → s ⟶∞ → s ⟶∞′
complete (s₁⟶s₂ ◅ s₂⟶∞) = _ ⟶⟨ s₁⟶s₂ ⟩′ ♯ complete (♭ s₂⟶∞)
module Functional where
data Result : Set where
continue : (s : State) → Result
done : (v : Value) → Result
crash : Result
step : State → Result
step ⟨ [] , val v ∷ [] , [] ⟩ = done v
step ⟨ Var x ∷ c , s , ρ ⟩ = continue ⟨ c , val (lookup x ρ) ∷ s , ρ ⟩
step ⟨ Con i ∷ c , s , ρ ⟩ = continue ⟨ c , val (con i) ∷ s , ρ ⟩
step ⟨ Clos c′ ∷ c , s , ρ ⟩ = continue ⟨ c , val (ƛ c′ ρ) ∷ s , ρ ⟩
step ⟨ App ∷ c , val v ∷ val (ƛ c′ ρ′) ∷ s , ρ ⟩ = continue ⟨ c′ , ret c ρ ∷ s , v ∷ ρ′ ⟩
step ⟨ Ret ∷ c , val v ∷ ret c′ ρ′ ∷ s , ρ ⟩ = continue ⟨ c′ , val v ∷ s , ρ′ ⟩
step _ = crash
exec : State → Maybe Value ⊥
exec s with step s
... | continue s′ = later (♯ exec s′)
... | done v = return (just v)
... | crash = return nothing
module Equality where
open P.Propositional public
using (_≈_; now; later; laterˡ; later⁻¹; now≉never)
renaming (module Reasoning to EqReasoning)
module Equivalence where
open Relational
open Functional
open Functional.Equality
data Crashing : State → Set where
crash₁ : ∀ {n ρ} → Crashing (⟨_,_,_⟩ { n} [] [] ρ )
crash₂ : ∀ {n n′ c ρ′ s ρ} → Crashing (⟨_,_,_⟩ { n} [] ( ret {n′} c ρ′ ∷ s ) ρ )
crash₃ : ∀ {n v e s ρ} → Crashing (⟨_,_,_⟩ { n} [] (val v ∷ e ∷ s ) ρ )
crash₄ : ∀ {n v₁ v₂ ρ} → Crashing (⟨_,_,_⟩ {suc n} [] ( val v₁ ∷ []) (v₂ ∷ ρ))
crash₅ : ∀ {n c ρ} → Crashing (⟨_,_,_⟩ { n} (App ∷ c) [] ρ )
crash₆ : ∀ {n c v ρ} → Crashing (⟨_,_,_⟩ { n} (App ∷ c) ( val v ∷ []) ρ )
crash₇ : ∀ {n c n′ c′ ρ′ s ρ} → Crashing (⟨_,_,_⟩ { n} (App ∷ c) ( ret {n′} c′ ρ′ ∷ s ) ρ )
crash₈ : ∀ {n c v i s ρ} → Crashing (⟨_,_,_⟩ { n} (App ∷ c) (val v ∷ val (con i) ∷ s ) ρ )
crash₉ : ∀ {n c v n′ c′ ρ′ s ρ} → Crashing (⟨_,_,_⟩ { n} (App ∷ c) (val v ∷ ret {n′} c′ ρ′ ∷ s ) ρ )
crash₁₀ : ∀ {n c ρ} → Crashing (⟨_,_,_⟩ { n} (Ret ∷ c) [] ρ )
crash₁₁ : ∀ {n c v ρ} → Crashing (⟨_,_,_⟩ { n} (Ret ∷ c) ( val v ∷ []) ρ )
crash₁₂ : ∀ {n c n′ c′ ρ′ s ρ} → Crashing (⟨_,_,_⟩ { n} (Ret ∷ c) ( ret {n′} c′ ρ′ ∷ s ) ρ )
crash₁₃ : ∀ {n c v₁ v₂ s ρ} → Crashing (⟨_,_,_⟩ { n} (Ret ∷ c) (val v₁ ∷ val v₂ ∷ s ) ρ )
data Kind (s : State) : Set where
done : ∀ {v} (s⇓v : s ⇓ v) → Kind s
continue : ∀ {s′} (s⟶s′ : s ⟶ s′) → Kind s
crash : (s↯ : Crashing s) → Kind s
kind : ∀ s → Kind s
kind ⟨ [] , val v ∷ [] , [] ⟩ = done final
kind ⟨ Var x ∷ c , s , ρ ⟩ = continue Var
kind ⟨ Con i ∷ c , s , ρ ⟩ = continue Con
kind ⟨ Clos c′ ∷ c , s , ρ ⟩ = continue Clos
kind ⟨ App ∷ c , val v ∷ val (ƛ c′ ρ′) ∷ s , ρ ⟩ = continue App
kind ⟨ Ret ∷ c , val v ∷ ret c′ ρ′ ∷ s , ρ ⟩ = continue Ret
kind ⟨ [] , [] , _ ⟩ = crash crash₁
kind ⟨ [] , ret _ _ ∷ _ , _ ⟩ = crash crash₂
kind ⟨ [] , val _ ∷ _ ∷ _ , _ ⟩ = crash crash₃
kind ⟨ [] , val _ ∷ [] , _ ∷ _ ⟩ = crash crash₄
kind ⟨ App ∷ _ , [] , _ ⟩ = crash crash₅
kind ⟨ App ∷ _ , val _ ∷ [] , _ ⟩ = crash crash₆
kind ⟨ App ∷ _ , ret _ _ ∷ _ , _ ⟩ = crash crash₇
kind ⟨ App ∷ _ , val _ ∷ val (con _) ∷ _ , _ ⟩ = crash crash₈
kind ⟨ App ∷ _ , val _ ∷ ret _ _ ∷ _ , _ ⟩ = crash crash₉
kind ⟨ Ret ∷ _ , [] , _ ⟩ = crash crash₁₀
kind ⟨ Ret ∷ _ , val _ ∷ [] , _ ⟩ = crash crash₁₁
kind ⟨ Ret ∷ _ , ret _ _ ∷ _ , _ ⟩ = crash crash₁₂
kind ⟨ Ret ∷ _ , val _ ∷ val _ ∷ _ , _ ⟩ = crash crash₁₃
exec-crashes : ∀ {s} → Crashing s → exec s ≈ return nothing
exec-crashes crash₁ = now PE.refl
exec-crashes crash₂ = now PE.refl
exec-crashes crash₃ = now PE.refl
exec-crashes crash₄ = now PE.refl
exec-crashes crash₅ = now PE.refl
exec-crashes crash₆ = now PE.refl
exec-crashes crash₇ = now PE.refl
exec-crashes crash₈ = now PE.refl
exec-crashes crash₉ = now PE.refl
exec-crashes crash₁₀ = now PE.refl
exec-crashes crash₁₁ = now PE.refl
exec-crashes crash₁₂ = now PE.refl
exec-crashes crash₁₃ = now PE.refl
⟶-crashes : ∀ {s} → Crashing s → Stuck s
⟶-crashes s↯ = (helper₁ s↯ , helper₂ s↯)
where
helper₁ : ∀ {s} → Crashing s → Final s
helper₁ crash₁ (_ , ())
helper₁ crash₂ (_ , ())
helper₁ crash₃ (_ , ())
helper₁ crash₄ (_ , ())
helper₁ crash₅ (_ , ())
helper₁ crash₆ (_ , ())
helper₁ crash₇ (_ , ())
helper₁ crash₈ (_ , ())
helper₁ crash₉ (_ , ())
helper₁ crash₁₀ (_ , ())
helper₁ crash₁₁ (_ , ())
helper₁ crash₁₂ (_ , ())
helper₁ crash₁₃ (_ , ())
helper₂ : ∀ {s} → Crashing s → ∄ λ v → s ⇓ v
helper₂ crash₁ (_ , ())
helper₂ crash₂ (_ , ())
helper₂ crash₃ (_ , ())
helper₂ crash₄ (_ , ())
helper₂ crash₅ (_ , ())
helper₂ crash₆ (_ , ())
helper₂ crash₇ (_ , ())
helper₂ crash₈ (_ , ())
helper₂ crash₉ (_ , ())
helper₂ crash₁₀ (_ , ())
helper₂ crash₁₁ (_ , ())
helper₂ crash₁₂ (_ , ())
helper₂ crash₁₃ (_ , ())
⇒⇓ : ∀ {s s′ v} → s ⟶⋆ s′ → s′ ⇓ v → exec s ≈ return (just v)
⇒⇓ ε final = now PE.refl
⇒⇓ (Var ◅ s⟶⋆) ⇓ = laterˡ (⇒⇓ s⟶⋆ ⇓)
⇒⇓ (Con ◅ s⟶⋆) ⇓ = laterˡ (⇒⇓ s⟶⋆ ⇓)
⇒⇓ (Clos ◅ s⟶⋆) ⇓ = laterˡ (⇒⇓ s⟶⋆ ⇓)
⇒⇓ (App ◅ s⟶⋆) ⇓ = laterˡ (⇒⇓ s⟶⋆ ⇓)
⇒⇓ (Ret ◅ s⟶⋆) ⇓ = laterˡ (⇒⇓ s⟶⋆ ⇓)
⇒⇑ : ∀ {s} → s ⟶∞ → exec s ≈ never
⇒⇑ (Var ◅ s⟶∞) = later (♯ (⇒⇑ (♭ s⟶∞)))
⇒⇑ (Con ◅ s⟶∞) = later (♯ (⇒⇑ (♭ s⟶∞)))
⇒⇑ (Clos ◅ s⟶∞) = later (♯ (⇒⇑ (♭ s⟶∞)))
⇒⇑ (App ◅ s⟶∞) = later (♯ (⇒⇑ (♭ s⟶∞)))
⇒⇑ (Ret ◅ s⟶∞) = later (♯ (⇒⇑ (♭ s⟶∞)))
⇒↯ : ∀ {s} → ∃ (λ s′ → s ⟶⋆ s′ × Stuck s′) → exec s ≈ return nothing
⇒↯ (_ , Var ◅ s⟶⋆ , ↯) = laterˡ (⇒↯ (_ , s⟶⋆ , ↯))
⇒↯ (_ , Con ◅ s⟶⋆ , ↯) = laterˡ (⇒↯ (_ , s⟶⋆ , ↯))
⇒↯ (_ , Clos ◅ s⟶⋆ , ↯) = laterˡ (⇒↯ (_ , s⟶⋆ , ↯))
⇒↯ (_ , App ◅ s⟶⋆ , ↯) = laterˡ (⇒↯ (_ , s⟶⋆ , ↯))
⇒↯ (_ , Ret ◅ s⟶⋆ , ↯) = laterˡ (⇒↯ (_ , s⟶⋆ , ↯))
⇒↯ (s , ε , ↯) with kind s
... | done s⇓v = ⊥-elim (proj₂ ↯ (, s⇓v))
... | continue s₁⟶s₂ = ⊥-elim (proj₁ ↯ (, s₁⟶s₂))
... | crash s↯ = exec-crashes s↯
⇐⇓ : ∀ {s v} → exec s ≈ return (just v) → ∃ λ s′ → s ⟶⋆ s′ × s′ ⇓ v
⇐⇓ {s = s} ⇓ with kind s
⇐⇓ (now PE.refl) | done final = (_ , ε , final)
⇐⇓ (laterˡ ⇓) | continue Var = Prod.map id (Prod.map (_◅_ Var ) id) (⇐⇓ ⇓)
⇐⇓ (laterˡ ⇓) | continue Con = Prod.map id (Prod.map (_◅_ Con ) id) (⇐⇓ ⇓)
⇐⇓ (laterˡ ⇓) | continue Clos = Prod.map id (Prod.map (_◅_ Clos) id) (⇐⇓ ⇓)
⇐⇓ (laterˡ ⇓) | continue App = Prod.map id (Prod.map (_◅_ App ) id) (⇐⇓ ⇓)
⇐⇓ (laterˡ ⇓) | continue Ret = Prod.map id (Prod.map (_◅_ Ret ) id) (⇐⇓ ⇓)
⇐⇓ {s} {v} ⇓ | crash s↯ with
return (just v) ≈⟨ sym ⇓ ⟩
exec s ≈⟨ exec-crashes s↯ ⟩
return nothing ∎
where open EqReasoning
... | now ()
⇐⇑ : ∀ {s} → exec s ≈ never → s ⟶∞
⇐⇑ {s = s} ⇑ with kind s
⇐⇑ ⇑ | done final = ⊥-elim (now≉never ⇑)
⇐⇑ ⇑ | continue Var = Var ◅ ♯ ⇐⇑ (later⁻¹ ⇑)
⇐⇑ ⇑ | continue Con = Con ◅ ♯ ⇐⇑ (later⁻¹ ⇑)
⇐⇑ ⇑ | continue Clos = Clos ◅ ♯ ⇐⇑ (later⁻¹ ⇑)
⇐⇑ ⇑ | continue App = App ◅ ♯ ⇐⇑ (later⁻¹ ⇑)
⇐⇑ ⇑ | continue Ret = Ret ◅ ♯ ⇐⇑ (later⁻¹ ⇑)
⇐⇑ {s} ⇑ | crash s↯ = ⊥-elim (now≉never (
return nothing ≈⟨ sym $ exec-crashes s↯ ⟩
exec s ≈⟨ ⇑ ⟩
never ∎))
where open EqReasoning
⇐↯ : ∀ {s} → exec s ≈ return nothing → ∃ λ s′ → s ⟶⋆ s′ × Stuck s′
⇐↯ {s = s} ↯ with kind s
⇐↯ (now ()) | done final
⇐↯ (laterˡ ↯) | continue Var = Prod.map id (Prod.map (_◅_ Var ) id) $ ⇐↯ ↯
⇐↯ (laterˡ ↯) | continue Con = Prod.map id (Prod.map (_◅_ Con ) id) $ ⇐↯ ↯
⇐↯ (laterˡ ↯) | continue Clos = Prod.map id (Prod.map (_◅_ Clos) id) $ ⇐↯ ↯
⇐↯ (laterˡ ↯) | continue App = Prod.map id (Prod.map (_◅_ App ) id) $ ⇐↯ ↯
⇐↯ (laterˡ ↯) | continue Ret = Prod.map id (Prod.map (_◅_ Ret ) id) $ ⇐↯ ↯
⇐↯ ↯ | crash s↯ = (_ , ε , ⟶-crashes s↯)