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), _⟩
Instances for computation.return
Equations
think c
is the computation that delays for one "tick" and then performs
computation c
.
Instances for computation.think
thinkN c n
is the computation that delays for n
ticks and then performs
computation c
.
Instances for computation.thinkN
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
think
s.
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
Recursion principle for computations, compare with list.rec_on
.
Equations
- s.rec_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), _⟩
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.
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 _
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, _⟩
Instances for computation.map
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)
Instances for computation.bind
Equations
Flatten a computation of computations into a single computation.
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
.