Research
λ calculus Agda Bidirectional Updating Burrows-Wheeler Transform Concurrency Converse-of-a-Function Theorem Curry-Howard Data Structure Dependent Type Fibonacci GADT Greedy Theorem Haskell HaXML List Homomorphism Logic Logic Programming Program Derivation Program Inversion Quantum Programming Quine Regular Expression Segment Problems Termination Thinning Theorem Types XML Streaming-
Recent Comments
- 先寬度標記 on Theory and applications of inverting functions as folds.
- Liang-Ting Chen on Proof Irrelevance, Extensional Equality, and the Excluded Middle
- Shin on Proof Irrelevance, Extensional Equality, and the Excluded Middle
- speleologic on Proof Irrelevance, Extensional Equality, and the Excluded Middle
- Dan Doel on No Inverses for Injective but Non-Surjective Functions?
“General Recursion using Coinductive Monad” Got Right
In the previous post I talked about encoding general recursion in Agda using a coinductive monad. One oddity was that Agda does not automatically unfold coinductive definitions, and a solution was to manually unfold them when we need. Therefore, instead of proving, for example, for coinductively defined
f:we prove a pair of (possibly mutually recursive) properties:
where
unfold(a user-defined function) performs the unfolding, and the second property follows from the first by≡-substand the fact thatunfold (f k n) ≡ f k n.While the use of
unfoldappears to be a direct work around, one may argue that this is merely treating the symptom. To resolve this and some other oddities, Anton Setzer argued in his letter “Getting codata right” (hence the title of this post) to the Agda mailing list that we should go back to a category theoretical view of codata, and Dan Doel soon successfully experimented the ideas. The following, however, are based on my current understanding of their work, which may not be matured yet.What
codataReally IsInductive datatypes are defined by describing how a value is constructed. The following inductive definition:
states that
[]is a list and, given an elementxand a listxs, one can construct a listx ∷ xs.Coinductive datatypes, on the other hand, are specified by how a covalue can be observed. The following definition of stream:
while looking almost identical to
Listapart from the use of keywordcodata, is in fact a definition very different from that ofListin nature. Setzer suggests seeing it as a short-hand for the following collection of definitions (in Setzer’s proposed notation but my naming scheme):Notice that
Stream aappears in the domain, rather than the range of_*because we are defining a coalgebra and_*is a deconstructor. My interpretation is that_*triggers an obserivation. Given a streamxs, an observationxs *yields two possible results. Either it isempty, ornonempty x xs', in the latter case we get its headxand tailxs'. The stream “constructors”, on the other hand, can be defined by:which states that
[]is the stream which, when observed, yieldsemptyandx ∷ xsis the stream whose observation isnonempty x xs.A coinductive definition:
is a shorthand for
That is,
f xdefines an coinductive object whose observation shall be the same as that ofe. Setzer proposes explicit notation (e.g.~ (x ∷ xs)) for pattern matching covalue. Back to current Agda, we may seen pattern matching covalue as implicitly applying_*and pattern-match the result. For example, the Agda program:can be seen as syntax sugar for:
Covalue-Indexed Types
What about (co)datatypes that are indexed by covalues? Take, for example, the codatatype
Comp afor possibly non-terminating computation, define in my previous post:and the datatype
_↓=_claiming that certain computation terminates and yields a value:What is the definition actually trying to say? Given
m : Comp aandx,m ↓= xis a type. In the case thatmisreturn x, there is an immediate proof, denoted by↓=-return, of(return x) ↓= x(that is,return xterminates with valuex). For the casem ⟩⟩= f, we can construct its termination proof, denoted by constructor↓=-bind, from termination proofs ofmandf x. Setzer suggests the following definition, which corresponds more literally to the verbal description above:Now
↓=-returnand↓=-bindare the only constructors of their own types, and_↓=_mapsComp atyped covalues to their termination proofs according to their observations. Notice that↓=-Returnis exactly the built-in identity type_≡_:return xterminates withyif and only ifxequalsy.For more examples, compare the valueless termination type
_↓in the previous post:and its “correct” representation:
Here is a non-recursive example. The datatype
Invoked-Bycharacterising sub-computation relation is written:Like above, we define a function for dispatching
Comp acovalues according to their observation:Indeed,
return xconsists of no sub-computations, thereforeinvoked-by m (return x)is an empty relation. On the other hand, there are two possibilitiesinvoked-by m (n ⟩⟩= f), represented by the two cases ofInvoked-By.Termination Proof
The lengthy discussion above is of more than pedantic interest. While the mutually exclusive indexed type definitions may look rather confusing to some, the effort pays off when we prove properties about them. Redoing the exercises in the previous post using the new definitions, the first good news is that the definitions of
Safe,↓-safe,eval-safe, andevalstay almost the same. Second, we no longer have to split the termination proofs into pairs.Take for example the McCarthian Maximum function:
Its termination proof is based on two lemmas, together they state that
f k nterminates with the maximum ofkandn:Divergence Proof
For some reason (lack of space, perhaps?), Megacz did not talk about divergence in his PLPV paper. For completeness, let us give it a try.
A
returncommand always terminates. On the other hand,m ⟩⟩= fdiverges if eithermdoes, orm ↓= xandf xdiverges. This is expressed as:For an example, the following is a proof that
lengthdiverges when applied to an infinite stream:The implicit argument
length onesmust be given. Otherwiselength-ones↑fails to typecheck when the file is loaded, although it does typecheck whenlength-ones↑was stepwisely constructed using the “Give” command. I do not know whether it is a bug in Agda.Programs
_≤′′_.