Here at Cedille HQ, we are still beavering away on … wait for it … lambda encodings! Seriously? You guys only do this? Well, if you asked me five years ago what would I be (still) working on five years in the future I would not have said lambda encodings. But maybe I would not have said “not lambda encodings” (I would have said, though, for dang sure, “not deep learning” :-)). Well, the reason we have to spend all this time on lambda encodings is that they determine the kind of terminating programs you can write in Cedille, where all data are lambda encoded and recursion is implemented just using the lambda encoding (so there is no recursion built in primitively to the system; rather, it is defined using a terminating fragment of pure typed lambda calculus). And if you asked me, do you think you will still be interested in programs — say software — in five years, I would have said emphatically yes — but not Software 2.0. 🙂

So what is a recursion universe? I hope I reveal something of my personality if I write that I think the name sounds super cool. 🙂 A recursion universe type-theoretically is a view R of an inductive datatype C, together with some operations on R that preserve termination in the presence of structural recursion. So the type R with those operations is an interface you can use when you are writing a structurally recursive (so terminating) function. Recursive calls may only be made on elements of type R. The interface permits you at least to escape the universe by converting a value of type R to C (at which point you cannot recurse on it any more) — this is what is meant by saying R is a view of C (I hope I have my terminology correct there on “view” — please comment if you think I have it scrambled).

Cedille 1.2 (current version) supports histomorphic recursion by — from the perspective of recursion universes — providing a recursion universe that has an operation out of type R -> F R, where F is the type scheme determining the datatype (so for Nat it would be λ X : ★ . Sum Unit X). Extracting subdata of type R from a value of type R is a termination-preserving operation: I cannot write a diverging function by structurally recursing on subdata of subdata if I was allowed to recurse on subdata.

This is a very simple recursion universe, but already it lets us express functions that go beyond what you can naturally write in Coq and Agda. Division by repeated subtraction using the out function to dig into the dividend (by subtracting the divisor) and still return something of type R, which the function can then recurse on. Cool!

The realization this past week was that we could hope to define more interesting recursion universes that would allow us to implement other patterns of terminating recursion. The one I have been after for one year now is divide and conquer, such as is needed for classic mergesort (split the input list roughly in two halves, recurse, then merge). Splitting the list in two halves and then recursing on the halves is not something you can do in Coq and Agda without reasoning about sizes. The goal here is to use non-dependent typing only, in order to enforce termination.

Well, having answered the first question in the title, I must leave you hanging for an answer to the second: I have some more work to do to extend Cedille’s recursion universe beyond just out. I can tell you that I do have an extension, but I am working on a more general one before I post again about this.