The final co-algebra of a multivariate qpf is again a qpf.
For a (n+1)
-ary QPF F (α₀,..,αₙ)
, we take the least fixed point of F
with
regards to its last argument αₙ
. The result is a n
-ary functor: fix F (α₀,..,αₙ₋₁)
.
Making fix F
into a functor allows us to take the fixed point, compose with other functors
and take a fixed point again.
Main definitions
cofix.mk
- constructor- `cofix.dest - destructor
cofix.corec
- corecursor: useful for formulating infinite, productive computationscofix.bisim
- bisimulation: proof technique to show the equality of possibly infinite values ofcofix F α
Implementation notes
For F
a QPF, we define
cofix F αin terms of the M-type of the polynomial functor
Pof
F.
We define the relation
Mcongrand take its quotient as the definition of
cofix F α`.
Mcongr
is taken as the weakest bisimulation on M-type. See
[avigad-carneiro-hudon2019] for more details.
Reference
- [Jeremy Avigad, Mario M. Carneiro and Simon Hudon, Data Types as Quotients of Polynomial Functors][avigad-carneiro-hudon2019]
corecF
is used as a basis for defining the corecursor of cofix F α
. corecF
uses corecursion to construct the M-type generated by q.P
and uses function on F
as a corecursive step
Equations
- mvqpf.corecF g = mvpfunctor.M.corec (mvqpf.P F) (λ (x : β), mvqpf.repr (g x))
Characterization of desirable equivalence relations on M-types
Equations
- mvqpf.is_precongr r = ∀ ⦃x y : (mvqpf.P F).M α⦄, r x y → mvqpf.abs (mvfunctor.map (typevec.id ::: quot.mk r) (mvpfunctor.M.dest (mvqpf.P F) x)) = mvqpf.abs (mvfunctor.map (typevec.id ::: quot.mk r) (mvpfunctor.M.dest (mvqpf.P F) y))
Equivalence relation on M-types representing a value of type cofix F
Equations
- mvqpf.Mcongr x y = ∃ (r : (mvqpf.P F).M α → (mvqpf.P F).M α → Prop), mvqpf.is_precongr r ∧ r x y
Greatest fixed point of functor F. The result is a functor with one fewer parameters
than the input. For F a b c
a ternary functor, fix F is a binary functor such that
cofix F a b = F a b (cofix F a b)
Equations
- mvqpf.cofix F α = quot mvqpf.Mcongr
Equations
- mvqpf.inhabited = {default := quot.mk mvqpf.Mcongr (inhabited.default ((mvqpf.P F).M α))}
the map function for the functor cofix F
Equations
- mvqpf.cofix.map g = quot.lift (λ (x : (mvqpf.P F).M α), quot.mk mvqpf.Mcongr (mvfunctor.map g x)) _
Equations
Corecursor for cofix F
Equations
- mvqpf.cofix.corec g = λ (x : β), quot.mk mvqpf.Mcongr (mvqpf.corecF g x)
Destructor for cofix F
Equations
- mvqpf.cofix.dest = quot.lift (λ (x : (mvqpf.P F).M α), mvfunctor.map (typevec.id ::: quot.mk mvqpf.Mcongr) (mvqpf.abs (mvpfunctor.M.dest (mvqpf.P F) x))) mvqpf.cofix.dest._proof_1
Abstraction function for cofix F α
Equations
- mvqpf.cofix.abs = quot.mk mvqpf.Mcongr
Representation function for cofix F α
Equations
Corecursor for cofix F
Equations
- mvqpf.cofix.corec'₁ g x = mvqpf.cofix.corec (λ (x : β), g id) x
More flexible corecursor for cofix F
. Allows the return of a fully formed
value instead of making a recursive call
Equations
- mvqpf.cofix.corec' g x = let f : (α ::: mvqpf.cofix F α).arrow (α ::: (mvqpf.cofix F α ⊕ β)) := typevec.id ::: sum.inl in mvqpf.cofix.corec (sum.elim (mvfunctor.map f ∘ mvqpf.cofix.dest) g) (sum.inr x)
Corecursor for cofix F
. The shape allows recursive calls to
look like recursive calls.
Equations
- mvqpf.cofix.corec₁ g x = mvqpf.cofix.corec' (λ (x : β), g sum.inl sum.inr x) x
constructor for cofix F
Equations
- mvqpf.cofix.mk = mvqpf.cofix.corec (λ (x : F (α ::: mvqpf.cofix F α)), mvfunctor.map (typevec.id ::: λ (i : mvqpf.cofix F α), i.dest) x)
Bisimulation principles for cofix F
The following theorems are bisimulation principles. The general idea
is to use a bisimulation relation to prove the equality between
specific values of type cofix F α
.
A bisimulation relation R
for values x y : cofix F α
:
- holds for
x y
:R x y
- for any values
x y
that satisfyR
, their root has the same shape and their children can be paired in such a way that they satisfyR
.
Bisimulation principle using map
and quot.mk
to match and relate children of two trees.
Bisimulation principle using liftr
to match and relate children of two trees.
Bisimulation principle using liftr'
to match and relate children of two trees.
Bisimulation principle the values ⟨a,f⟩
of the polynomial functor representing
cofix F α
as well as an invariant Q : β → Prop
and a state β
generating the
left-hand side and right-hand side of the equality through functions u v : β → cofix F α
liftr_map
, liftr_map_last
and liftr_map_last'
are useful for reasoning about
the induction step in bisimulation proofs.
tactic for proof by bisimulation
tactic for proof by bisimulation
Equations
- mvqpf.mvqpf_cofix = {P := (mvqpf.P F).Mp, abs := λ (α : typevec n), quot.mk mvqpf.Mcongr, repr := λ (α : typevec n), mvqpf.cofix.repr, abs_repr := _, abs_map := _}