An advantage of explicit partiality

Suppose you have two computations which potentially diverge, and want to run both, returning a result if either of the computations return with a result. How can you accomplish this?

With naïve implementations of these computations in most programming languages, the task is impossible (barring perhaps use of concurrency primitives whose complexity is overkill here). This is because the partiality of these two computations is implicit in their code; that is, they are partial due to the use of fundamental programming constructs such as general recursion or while loops.

Often those who encounter languages marketed as “total” such as Coq and Agda doubt that these languages can be pragmatic. They fear that they will be unable to write computations which potentially diverge. It is true that Coq and Agda forbid implicit partiality; they keep you honest! If you claim to produce a value of type A, you must guarantee you produce such a value.

But it is easy to introduce explicit partiality with a higher-order coinductive type we’ll call Partial (using Coq notation here):

Let’s return to the original question: how do we merge two partial computations to return a result if either of them eventually returns a result? With explicit partiality, it’s a straightforward functional program:

One can introduce explicit partiality in many programming languages, but few, such as Coq, facilitate guaranteeing the lack of implicit partiality. By forbidding implicit partiality, Coq achieves the best of both worlds. Because Coq is total, its type system funtions as a logic. Totality also yields other benefits: for instance, strict and lazy evaluation always return the same answer, and parametricity theorems are stronger. By allowing explicit partiality with the coinductive Partial type, Coq is easily seen as Turing-complete. Even if we wish to write functions which are in fact provably total in Coq’s logic, we can avoid having to bake the termination proof into the function definition itself (which in general can cause an arbitrarily large blow-up factor in code size; see Bob Harper’s Old neglected theorems are still theorems). Best of all, we can compute the parallel-or for any partial computations.