open import Definition.Typed.Restrictions
open import Graded.Modality
open import Graded.Mode
module Definition.Typed.Decidable.Internal.Monad
{a a′} {M : Set a} {Mode : Set a′}
{𝕄 : Modality M}
(𝐌 : IsMode Mode 𝕄)
(TR : Type-restrictions 𝕄)
where
open import Definition.Typed.Decidable.Internal.Constraint 𝐌 TR
open import Definition.Typed.Decidable.Internal.Term 𝐌 TR
open import Definition.Untyped M using (Term-kind)
open import Tools.Bool
open import Tools.Function
open import Tools.Level as L
open import Tools.List
open import Tools.Maybe using (Maybe; just; nothing)
open import Tools.Nat using (Nat)
open import Tools.Product
import Tools.PropositionalEquality as PE
open import Tools.String
open import Tools.Sum
open import Tools.Unit
open Any using (Any)
private variable
ℓ ℓ₁ ℓ₂ : L.Level
A B : Set _
x y z : A
f : A → B
xs ys : List _
b : Bool
m n n₁ n₂ : Nat
c : Constants
γ : Contexts _
C : Constraint _
k : Term-kind
data Call (c : Constants) : Set a where
[red] [red-ty] [red-level] [check-type] [check-level] [infer]
[normalise-level] :
Cons c m n → Term[ c , k ] n → Call c
[red-tm] [check] [equal-ty] [equal-ne-inf] :
Cons c m n → (_ _ : Term[ c , k ] n) → Call c
[equal-tm] :
Cons c m n → (_ _ _ : Term[ c , k ] n) → Call c
[check-sub] :
DCon c m → Con c n₂ → Subst c n₂ n₁ → Con c n₁ → Call c
Stack-trace : Constants → Set a
Stack-trace c = List (Call c)
private variable
cl : Call _
st : Stack-trace _
record Monad-con (c : Constants) : Set a where
constructor _#_
no-eta-equality
field
contexts : Contexts c
stack-trace : Stack-trace c
open Monad-con public
record Check (c : Constants) (A : Set ℓ) : Set (lsuc a ⊔ ℓ) where
constructor wrap
no-eta-equality
field
run : Monad-con c → String × List (Call c) ⊎ A
open Check public
private variable
chk : Check _ _
fail : String → Check c A
fail s .run Μ = inj₁ (s , Μ .stack-trace)
register : Call c → Check c A → Check c A
register c comp .run Μ =
comp .run (record Μ { stack-trace = c ∷ Μ .stack-trace })
ask : Check c (Contexts c)
ask .run γ = inj₂ (γ .contexts)
infixr 2 _catch_
_catch_ : Check c A → Check c A → Check c A
(m₁ catch m₂) .run γ with m₁ .run γ
… | inj₁ _ = m₂ .run γ
… | x@(inj₂ _) = x
return : A → Check c A
return x .run _ = inj₂ x
infixl 1 _>>=_
_>>=_ : Check c A → (A → Check c B) → Check c B
(m >>= f) .run γ with m .run γ
… | inj₁ s = inj₁ s
… | inj₂ x with f x .run γ
… | inj₁ s = inj₁ s
… | inj₂ y = inj₂ y
infixl 1 _>>_
_>>_ : Check c A → Check c B → Check c B
x >> y = x >>= λ _ → y
infixl 3 _<$>_
_<$>_ : (A → B) → Check c A → Check c B
f <$> x = do
x ← x
return (f x)
infixl 3 _⊛_
_⊛_ : Check c (A → B) → Check c A → Check c B
f ⊛ x = do
f ← f
x ← x
return (f x)
unless : Bool → Check c ⊤ → Check c ⊤
unless true _ = return tt
unless false x = x
and : Check c Bool → Check c Bool → Check c Bool
and x y = do
b ← x
if b then y else return false
or : Check c Bool → Check c Bool → Check c Bool
or x y = do
b ← x
if b then return true else y
all : (A → Check c ⊤) → List A → Check c ⊤
all _ [] = return tt
all f (x ∷ xs) = f x >> all f xs
any : (A → Check c ⊤) → List A → Check c ⊤
any _ [] = fail "Empty list."
any f (x ∷ xs) = f x catch any f xs
require : Constraint c → Check c ⊤
require C = do
γ ← ask
unless (satisfied? C γ) (fail "Failed to verify constraint.")
require⁰ : Constraint⁰ → Check c ⊤
require⁰ = require ∘→ constr⁰
require⁺ : Constraint⁺ c → Check c ⊤
require⁺ = require ∘→ constr⁺
equality-reflection-disallowed? : Check c Bool
equality-reflection-disallowed? = do
γ ← ask
return (satisfied?⁰ no-equality-reflection γ)
if-no-equality-reflection : Check c A → Check c A → Check c A
if-no-equality-reflection x y = do
disallowed ← equality-reflection-disallowed?
if disallowed then x else y
infix 4 [_]with-message_
[_]with-message_ : Maybe A → String → Check c A
[ just x ]with-message _ = return x
[ nothing ]with-message s = fail s
Fuel : Set
Fuel = Nat
no-fuel : Check c A
no-fuel .run _ = inj₁ ("No fuel left." , [])
data OK {A : Set ℓ} (x : Check c A) (y : A) (γ : Contexts c)
(st : Stack-trace c) : Set (lsuc a ⊔ ℓ) where
ok : x .run (γ # st) PE.≡ inj₂ y → OK x y γ st
pattern not-ok = ok ()
pattern ok! = ok PE.refl
opaque
OK-register :
OK x y γ (cl ∷ st) →
OK (register cl x) y γ st
OK-register (ok eq) = ok eq
opaque
inv-register :
OK (register cl chk) x γ st →
OK chk x γ (cl ∷ st)
inv-register (ok eq) = ok eq
opaque
OK-catch :
(∃ λ z → OK x z γ st) ⊎ (∃ λ z → OK y z γ st) →
∃ λ z → OK (x catch y) z γ st
OK-catch eq = let _ , eq = lemma eq in _ , ok eq
where
lemma :
(∃ λ z → OK x z γ st) ⊎ (∃ λ z → OK y z γ st) →
∃ λ z → (x catch y) .run (γ # st) PE.≡ inj₂ z
lemma {x} {γ} {st} (inj₁ (_ , ok _)) with x .run (γ # st)
lemma (inj₁ (_ , not-ok)) | inj₁ _
lemma _ | inj₂ _ = _ , PE.refl
lemma {x} {γ} {st} (inj₂ _) with x .run (γ # st)
lemma _ | inj₂ _ = _ , PE.refl
lemma {γ} {st} {y} (inj₂ (_ , ok _)) | inj₁ _ with y .run (γ # st)
lemma (inj₂ (_ , not-ok)) | inj₁ _ | inj₁ _
lemma _ | inj₁ _ | inj₂ _ =
_ , PE.refl
opaque
inv-catch : OK (x catch y) z γ st → OK x z γ st ⊎ OK y z γ st
inv-catch {x} {γ} {st} (ok eq) with x .run (γ # st) in eq
inv-catch (ok PE.refl) | inj₂ _ = inj₁ (ok eq)
inv-catch (ok eq ) | inj₁ _ = inj₂ (ok eq)
opaque
OK->>= :
OK x y γ st → OK (f y) z γ st → OK (x >>= f) z γ st
OK->>= eq₁ eq₂ = ok (lemma eq₁ eq₂)
where
lemma :
OK x y γ st → OK (f y) z γ st →
(x >>= f) .run (γ # st) PE.≡ inj₂ z
lemma {x} {γ} {st} (ok _) _ with x .run (γ # st)
lemma not-ok _ | inj₁ _
lemma {γ} {st} {f} ok! (ok _) | inj₂ y with f y .run (γ # st)
lemma ok! not-ok | inj₂ _ | inj₁ _
lemma ok! ok! | inj₂ _ | inj₂ _ = PE.refl
record Inv->>= {A : Set ℓ₁} {B : Set ℓ₂}
(x : Check c A) (f : A → Check c B) (y : B) (γ : Contexts c)
(st : Stack-trace c) : Set (lsuc a ⊔ ℓ₁ ⊔ ℓ₂) where
constructor inv
field
value : A
ok₁ : OK x value γ st
ok₂ : OK (f value) y γ st
opaque
inv->>= : OK (x >>= f) y γ st → Inv->>= x f y γ st
inv->>= {x} {γ} {st} (ok _) with x .run (γ # st) in eq₁
inv->>= not-ok | inj₁ _
inv->>= {f} {γ} {st} _ | inj₂ y
with f y .run (γ # st) in eq₂
inv->>= not-ok | _ | inj₁ _
inv->>= (ok PE.refl) | inj₂ y | inj₂ _ =
inv y (ok eq₁) (ok eq₂)
data Inv-<$> {A : Set ℓ₁} {B : Set ℓ₂}
(f : A → B) (x : Check c A) (y : B) (γ : Contexts c)
(st : Stack-trace c) : Set (lsuc a ⊔ ℓ₁ ⊔ ℓ₂) where
inv : ∀ x′ → OK x x′ γ st → f x′ PE.≡ y → Inv-<$> f x y γ st
opaque
inv-<$> : OK (f <$> x) y γ st → Inv-<$> f x y γ st
inv-<$> eq
with inv->>= eq
… | inv _ eq ok! =
inv _ eq PE.refl
data Inv-⊛ {A : Set ℓ₁} {B : Set ℓ₂}
(f : Check c (A → B)) (x : Check c A) (y : B) (γ : Contexts c)
(st : Stack-trace c) : Set (lsuc a ⊔ ℓ₁ ⊔ ℓ₂) where
inv : ∀ f′ x′ → OK f f′ γ st → OK x x′ γ st → f′ x′ PE.≡ y →
Inv-⊛ f x y γ st
opaque
inv-⊛ : OK (x ⊛ y) z γ st → Inv-⊛ x y z γ st
inv-⊛ eq
with inv->>= eq
… | inv _ eq₁ eq
with inv->>= eq
… | inv _ eq₂ ok! =
inv _ _ eq₁ eq₂ PE.refl
opaque
inv-unless : b PE.≡ false → OK (unless b x) tt γ st → OK x tt γ st
inv-unless PE.refl = idᶠ
opaque
inv-and : OK (and x y) true γ st → OK x true γ st × OK y true γ st
inv-and eq
with inv->>= eq
… | inv false _ not-ok
… | inv true eq₁ eq₂ =
eq₁ , eq₂
opaque
inv-or : OK (or x y) true γ st → OK x true γ st ⊎ OK y true γ st
inv-or eq with inv->>= eq
… | inv true eq ok! = inj₁ eq
… | inv false _ eq = inj₂ eq
opaque
inv-all : OK (all f xs) tt γ st → All (λ x → OK (f x) tt γ st) xs
inv-all {xs = []} ok! = []
inv-all {xs = _ ∷ _} eq
with inv->>= eq
… | inv _ eq₁ eq =
eq₁ ∷ inv-all eq
opaque
inv-any : OK (any f xs) tt γ st → Any (λ x → OK (f x) tt γ st) xs
inv-any {xs = []} not-ok
inv-any {xs = _ ∷ _} eq
with inv-catch eq
… | inj₁ eq =
here eq
… | inj₂ eq =
there (inv-any eq)
opaque
inv-require-T : ∀ C → OK (require C) tt γ st → T (satisfied? C γ)
inv-require-T {γ} C (ok _) with satisfied? C γ
inv-require-T _ not-ok | false
inv-require-T _ ok! | true = tt
opaque
OK-equality-reflection-disallowed? :
∃ λ b → OK equality-reflection-disallowed? b γ st
OK-equality-reflection-disallowed? =
_ , OK->>= ok! ok!
opaque
inv-equality-reflection-disallowed?-T :
OK equality-reflection-disallowed? true γ st →
T (γ .constraints⁰ .no-equality-reflection?)
inv-equality-reflection-disallowed?-T eq
with inv->>= eq
… | inv _ ok! (ok eq) =
T-true .proj₂ (inj₂-injective eq)
opaque
OK-if-no-equality-reflection :
OK x z γ st → OK y z γ st →
OK (if-no-equality-reflection x y) z γ st
OK-if-no-equality-reflection {γ} {st} eq₁ eq₂
with OK-equality-reflection-disallowed? {γ = γ} {st = st}
… | true , eq = OK->>= eq eq₁
… | false , eq = OK->>= eq eq₂
opaque
inv-if-no-equality-reflection-∈ :
OK (if-no-equality-reflection x y) z γ st →
T (γ .constraints⁰ .no-equality-reflection?) × OK x z γ st ⊎
OK y z γ st
inv-if-no-equality-reflection-∈ eq with inv->>= eq
… | inv false _ eq₂ = inj₂ eq₂
… | inv true eq₁ eq₂ =
inj₁ (inv-equality-reflection-disallowed?-T eq₁ , eq₂)