Chapter 6 Pattern Matching for Dependent Types
6.3 recognising programs
6.4.2 more exotic recursion
While it is sufficient to facilitate functions which are only recursive on one argument position, it is nonetheless convenient to allow more complex structures to be built into a single function, rather than forcing the programmer to break them up. The traditional example is Ackermann’s function:
;Ak D 88&«88$ 88 ;Ak SÙG = G ;AkÞ= S ;4k = S ;AkÞ= = G ;Ak ;AkÙ= G
The recursion in this function is lexicographic in the sense that either the first argument decreases structurally, or else it stays the same, but the second argument decreases. It can be split into a pair of Coquand-accepted primitive recursive functionals as follows:
;Ak ¯ D 88 88 «88$ 88 ;Ak ¯ ÂMÍ S Â7[Í = S ;Ak ¯ ÂMÍ = G Â7[Í ;Ak ¯ ÂMÍ G ;Ak D 88&«88$ 88 ;Ak S = ;AkÞ= ;Ak ¯ ;Ak
What has happened here? For a start, the main ;Ak function has been ’d into a
functional. This enables the =
case to be delegated to the auxiliary function;Ak ¯
This receives as an argument the function;Ak , available by structural recursion—it
is thus free to apply this function, as well as making its own guarded calls.8
Would not all but the most die-hard of origami programmers9prefer to write the lex-
icographic version? In fact, we already have the tools to construct it interactively— suppose we have reached the following stage:
X Ê k DEp GÉD 88KJMLMNPORQ XR [Aoo DEp GÉD 88KJ Ê k G 88 X Ç ýÆÇÇ ä DEp GÉD 88KJM88 Ê k G ;Ak ® Y ? D ÏÏ Y G D 88 = G XM;Ak ¯ DE D 88 E ? D EHGÅD 88ªJ Ê k G sÐÞ 88 Ê ¥¦Ë J7JMJ EG D 88 Ê kº= G ;Ak 88 © g˺J7JMJ The B}
argument gives us access to guarded recursion on the first argument. We may now add guarded recursion on the second (for the same first argument) by eliminating
G with88 © gË , fixing and? : XM;Ak ¯ DVEp D 88 E ? D EHGÉD 88ªJ Ê k G sÐ( 88 Ê ¥yË J7J7J EHG D 88 E ? C D 88 Ê ¥yË Ê kº= G Ê kÞ= G Case splitting onG now gives us
8We would not need to pass
!" #%$ explicitly through the recursion if we could define&(')+*$ locally
to the successor case of&,'-) .
XM;Ak D}Ep D 88 E ? D EHGÅD 88ªJ Ê k G ]Ð: 88 Ê ¥yË J7J7J E ?'C D ÏÏ Ê kÞ= &S XM;Ak ¯¯ D}Ep D 88 E ? D EHGÅD 88ªJ Ê k G ]Ð: 88 Ê ¥yË J7J7J EHG D 88 E ?'C D Ê kÞ= G sÐ( 88 Ê ¥yË Ê kÙ= G Ê kÞ= = G For the ;4k ¯®
case, we may project the appropriate component of B}
. Looking at
;Ak ¯¯
in more detail, the nested right-hand side translates by [Aoo and ÇýÆÇ Ç ä to XM;Ak ¯¯ D Y D 88 Y ? D EHGÅD 88ªJ Ê k G sÐÞ 88 Ê ¥¦Ë J7JMJ Y G D 88 Y ? C D Ê kÞ= G sÐ: 88 Ê ¥¦Ë Ê kÙ= G X ?K D Ê kÙ= G X ?RM D Ê k [Aoo ?K Ç ýÆÇ Ç ä [4oo ?VM ?K is solved from B} C and?RM is solved from ?
. The definition is complete.
We can build quite complex structures with multiple eliminations by guarded recursion—more even than lexicographic recursion on a number of argument posi- tions. For example, we may define a function on lists of trees which at each recursion replaces the head tree by its subtrees—some steps may make the list longer, but the decomposition of the head tree guarantees termination.
The question of how to extend the class of recognisable pattern matching programs into this more exotic territory is an important and interesting one. Much attention has already been paid to the simply typed case, for example, in Manoury and Simonot’s ‘ProPre’ [MS94] system. Further, Cristina Cornes has equipped COQwith a substantial
package translating equational programs with relatively interesting recursive structure into constructor guarded fixpoint expressions [Cor97].
Further investigation is beyond the scope of this thesis. However, I shall nonetheless write such equational programs in the following chapter, since they are shorter and clearer than their expanded versions where each recursion has its own subfunction. When I do so, I shall always be careful to point out the justification, imagining that we are deriving the function interactively.