Copatterns: the final approach to codata?

Andreas Abel and Brigitte Pientka's Well-Founded Recursion with Copatterns; a Unified Approach to Termination and Productivity is one of my highlights of the just-finished ICFP 2013, but it makes sense to focus on the first paper on this work, published at POPL back in January.

Copatterns: Programming Infinite Structures by Observations
Andreas Abel, Brigitte Pientka, David Thibodeau, Anton Setzer
2013

Inductive datatypes provide mechanisms to define finite data such as finite lists and trees via constructors and allow programmers to analyze and manipulate finite data via pattern matching. In this paper, we develop a dual approach for working with infinite data structures such as streams. Infinite data inhabits coinductive datatypes which denote greatest fixpoints. Unlike finite data which is defined by constructors we define infinite data by observations. Dual to pattern matching, a tool for analyzing finite data, we develop the concept of copattern matching, which allows us to synthesize infinite data. This leads to a symmetric language design where pattern matching on finite and infinite data can be mixed. We present a core language for programming with infinite structures by observations together with its operational semantics based on (co)pattern matching and describe coverage of copatterns. Our language naturally supports both call-by-name and call-by-value interpretations and can be seamlessly integrated into existing languages like Haskell and ML. We prove type soundness for our language and sketch how copatterns open new directions for solving problems in the interaction of coinductive and dependent types.

Codata has been often discussed here and elsewhere. See notably the discussion on Turner's Total Functional Programming (historical note: this 2004 beautification of the original 1995 paper which had much of the same ideas), and on the category-theory-inspired Charity language. Given those precedents, it would be easy for the quick reader to "meh" on the novelty of putting "observation" first (elimination rather than introduction rules) when talking about codata; yet the above paper is the first concrete, usable presentation of an observation in a practical setting that feels right, and it solves long-standing problem that current dependently-typed languages (Coq and Agda) have.

Coinduction has an even more prominent role, due to its massive use to define program equivalence in concurrent process calculi; the relevant LtU discussion being about Davide Sangiorgi's On the origins of Bisimulation, Coinduction, and Fixed Points. The POPL'13 paper doesn't really tell us how coinduction should be seen with copatterns. It does not adress the question of termination, which is the topic of the more recent ICFP'13 paper, but I would say that the answer on that point feels less definitive.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Thanks. Great first post!

Thanks, this is fascinating stuff. Great first post!

Typo: s/Andreal/Andreas/

And yes, great stuff.

Copatterns: not the final approach to codata

The most significant contribution of Abel and Pientka's ICFP paper is
easy to overlook. Andreas has mentioned it only in passing, in a
couple of words at the very end of his ICFP talk. I have later checked
with both authors to make sure I got it.

The common wisdom is that we use induction with inductive definitions,
and co-induction, and co-inductive proofs with codata such as Streams.
Induction is well-known and well-mechanized. To check that a
definition is really inductive, a proof assistant merely needs to check
coverage and termination. Although both tasks are generally very hard,
there is a lot of experience with them and there are lots of
good techniques for wide classes of problems.

With co-data, we need a so-called productivity check. Although some
form of it is implemented in Coq, it is rather fickle, hard to
understand, and mainly, quite limiting: not accepting many interesting
and correct programs on streams. The talk gave a few
examples. Co-inductive proofs require new tactics and techniques.

Abel and Pientka's paper reduces co-induction to the ordinary
induction, replacing coinductive proofs with (less ordinary) inductive
proofs. This is a big deal for implementors of proof assistant
(both authors are such implementors). The fewer facilities to
implement in the kernel of the proof assistant, the better. Avoiding
implementing the productivity check is a bonus.

The key to this is transfinite induction. It is transfinite
induction that lets us reason about potentially infinite streams.
Bringing-in transfinite induction in a proof-assistant--friendly
way is the real contribution.

Transfinite induction?

Can you elaborate on that last paragraph? Where's the step to limit ordinals?

See Section 4.2 of the

See Section 4.2 of the linked paper. Instead of using traditional transfinite induction in terms of successor and limit ordinals, which is not intuitionistically valid, they use well-founded induction in terms of inflationary and deflationary iterative steps.

I understood Oleg to be

I understood Oleg to be saying that the paper introduces a way to do transfinite induction using copatterns or some feature of their proposal, not just that they use transfinite induction in their proof. He wrote:

Bringing-in transfinite induction in a proof-assistant--friendly way is the real contribution.

Do you understand how this works? In section 4.2 that you pointed me to, they reason that,

Since the set Exp of expressions is countable and all elements of these chains are subsets of Exp, the chains must become stationary latest at the first uncountable ordinal Omega.

If they're only doing transfinite induction up to the first uncountable ordinal in proving the mechanism correct, it seems surprising that we could recover general transfinite induction using the mechanism. But my intuitionist abilities are weak, so maybe that's not true.