computation α is the type of unbounded computations returning α.
An element of computation α is an infinite sequence of option α such
that if f n = some a for some n then it is constantly some a after that.
Equations
- computation α = {f // ∀ {n : ℕ} {a : α}, f n = option.some a → f (n + 1) = option.some a}
return a is the computation that immediately terminates with result a.
Equations
- computation.return a = ⟨stream.const (option.some a), _⟩
Equations
think c is the computation that delays for one "tick" and then performs
computation c.
thinkN c n is the computation that delays for n ticks and then performs
computation c.
head c is the first step of computation, either some a if c = return a
or none if c = think c'.
tail c is the remainder of computation, either c if c = return a
or c' if c = think c'.
empty α is the computation that never returns, an infinite sequence of
thinks.
Equations
Equations
run_for c n evaluates c for n steps and returns the result, or none
if it did not terminate after n steps.
Equations
destruct c is the destructor for computation α as a coinductive type.
It returns inl a if c = return a and inr c' if c = think c'.
Equations
- c.destruct = computation.destruct._match_1 c (c.val 0)
- computation.destruct._match_1 c (option.some a) = sum.inl a
- computation.destruct._match_1 c option.none = sum.inr c.tail
run c is an unsound meta function that runs c to completion, possibly
resulting in an infinite loop in the VM.
Equations
- s.cases_on h1 h2 = (λ (_x : α ⊕ computation α) (H : s.destruct = _x), sum.rec (λ (v : α) (H : s.destruct = sum.inl v), _.mpr (h1 v)) (λ (v : computation α) (H : s.destruct = sum.inr v), subtype.cases_on v (λ (a : stream (option α)) (s' : ∀ {n : ℕ} {a_1 : α}, a n = option.some a_1 → a (n + 1) = option.some a_1) (H : s.destruct = sum.inr ⟨a, s'⟩), _.mpr (h2 ⟨a, s'⟩)) H) _x H) s.destruct _
Equations
- computation.corec.F f (sum.inr b) = (computation.corec.F._match_1 (f b), f b)
- computation.corec.F f (sum.inl a) = (option.some a, sum.inl a)
- computation.corec.F._match_1 (sum.inr b') = option.none
- computation.corec.F._match_1 (sum.inl a) = option.some a
corec f b is the corecursor for computation α as a coinductive type.
If f b = inl a then corec f b = return a, and if f b = inl b' then
corec f b = think (corec f b').
Equations
- computation.corec f b = ⟨stream.corec' (computation.corec.F f) (sum.inr b), _⟩
left map of ⊕
Equations
- computation.lmap f (sum.inr b) = sum.inr b
- computation.lmap f (sum.inl a) = sum.inl (f a)
right map of ⊕
Equations
- computation.rmap f (sum.inr b) = sum.inr (f b)
- computation.rmap f (sum.inl a) = sum.inl a
Equations
- computation.bisim_o R (sum.inr s) (sum.inr s') = R s s'
- computation.bisim_o R (sum.inr val) (sum.inl val_1) = false
- computation.bisim_o R (sum.inl val) (sum.inr val_1) = false
- computation.bisim_o R (sum.inl a) (sum.inl a') = (a = a')
Equations
- computation.is_bisimulation R = ∀ ⦃s₁ s₂ : computation α⦄, R s₁ s₂ → computation.bisim_o R s₁.destruct s₂.destruct
Equations
- computation.mem a s = (option.some a ∈ s.val)
Equations
terminates s asserts that the computation s eventually terminates with some value.
Equations
- s.terminates = ∃ (a : α), a ∈ s
Equations
- _ = _
Equations
- _ = _
Equations
- _ = _
promises s a, or s ~> a, asserts that although the computation s
may not terminate, if it does, then the result is a.
length s gets the number of steps of a terminating computation
get s returns the result of a terminating computation
Equations
- s.get = option.get _
results s a n completely characterizes a terminating computation:
it asserts that s terminates after exactly n steps, with result a.
Equations
- computation.mem_rec_on M h1 h2 = _.mpr (_.mpr (nat.rec h1 (λ (n : ℕ) (IH : C ((computation.return a).thinkN n)), h2 ((computation.return a).thinkN n) IH) s.length))
Equations
- s.terminates_rec_on h1 h2 = computation.mem_rec_on _ (h1 s.get) h2
Map a function on the result of a computation.
Equations
- computation.map f ⟨s, al⟩ = ⟨stream.map (λ (o : option α), o.cases_on option.none (option.some ∘ f)) s, _⟩
Equations
- computation.bind.G (sum.inr cb') = sum.inr (sum.inr cb')
- computation.bind.G (sum.inl b) = sum.inl b
Equations
- computation.bind.F f (sum.inr cb) = computation.bind.G cb.destruct
- computation.bind.F f (sum.inl ca) = computation.bind.F._match_1 f ca.destruct
- computation.bind.F._match_1 f (sum.inr ca') = sum.inr (sum.inl ca')
- computation.bind.F._match_1 f (sum.inl a) = computation.bind.G (f a).destruct
Compose two computations into a monadic bind operation.
Equations
- c.bind f = computation.corec (computation.bind.F f) (sum.inl c)
Equations
Flatten a computation of computations into a single computation.
Equations
- _ = _
Equations
Equations
Equations
- _ = _
c₁ <|> c₂ calculates c₁ and c₂ simultaneously, returning
the first one that gives a result.
Equations
- c₁.orelse c₂ = computation.corec (λ (_x : computation α × computation α), computation.orelse._match_3 _x) (c₁, c₂)
- computation.orelse._match_3 (c₁, c₂) = computation.orelse._match_1 c₂ c₁.destruct
- computation.orelse._match_1 c₂ (sum.inr c₁') = computation.orelse._match_2 c₁' c₂.destruct
- computation.orelse._match_1 c₂ (sum.inl a) = sum.inl a
- computation.orelse._match_2 c₁' (sum.inr c₂') = sum.inr (c₁', c₂')
- computation.orelse._match_2 c₁' (sum.inl a) = sum.inl a
Equations
c₁ ~ c₂ asserts that c₁ and c₂ either both terminate with the same result,
or both loop forever.
lift_rel R ca cb is a generalization of equiv to relations other than
equality. It asserts that if ca terminates with a, then cb terminates with
some b such that R a b, and if cb terminates with b then ca terminates
with some a such that R a b.
Equations
- computation.lift_rel_aux R C (sum.inr ca) (sum.inr cb) = C ca cb
- computation.lift_rel_aux R C (sum.inr ca) (sum.inl b) = ∃ {a : α}, a ∈ ca ∧ R a b
- computation.lift_rel_aux R C (sum.inl a) (sum.inr cb) = ∃ {b : β}, b ∈ cb ∧ R a b
- computation.lift_rel_aux R C (sum.inl a) (sum.inl b) = R a b