FORMAL REPRESENTATIONS
FOR RECURSIVELY DEFINED F U N C T I O N A L P R O G R A M S
John H. Williams
IBM Research Laboratory
5600 Cottle Road
San Jose, California 95193
Introduction
In [Ba 78] Backus shows how a formal system for functional programming (FFP) can be
used to represent all of the objects, primitive functions, and combining forms contained in his
informal system of functional p r o g r a m m i n g (FP).
In particular, using the rule of
metacomposition from his definition of the meaning function /~ of the F F P system, he shows
how each of the combining forms of FP can be realized as sequences in FFP. He also states,
"in addition to its use in defining functional forms, metacomposition can be used to create
recursive functions directly without the use of recursive definitions of the form"
Def f = E l ,
and he shows by way of example that the object
function defined by:
<LAST>
will correctly represent the FP
Def last = null o tl -~ 1 ; last o tl
if L A S T
is t a k e n to be the FFP object that represents the (nonrecursive) function
n u l l o t l o 2 -~ 1 02; A P P L Y o [ 1 , r i o 2 ] .
One can verify that the meaning of
<LAST>
applied to the sequence
<A, B>
is indeed
B, i.e. that
#(<LAST>:<A, B>)
-- B
and in general that
#(<LAST>:<Xl,
when
<X 1 ....
,
.- , Xn>)
= xn
Xn> is a constant expression of FFP.
It is remarkable that by using such a simple device as metacomposition Backus was able
to represent such recursively defined functions without relying on the existence of the (rather
complicated) Y combinator of [Ch 41] and [Cu 58] or introducing into his system an
additional m e c h a n i s m to m a i n t a i n an e n v i r o n m e n t of n a m e / v a l u e bindings and a special
"labeling" form as was done in Lisp [Me 60]. In fact, so powerful is the added e n v i r o n m e n t
of Lisp that the introduction of the special form L A B E L is actually unnecessary. To
represent the function defined by
D E F I N E (LAST (~ (X) ELAST))
we can use the pure Lisp expression
461
(X (X) ((2, (LAST) (LAST X ) ) ( Q U O T E (X (X) ELAST))) )
instead of the special form
( L A B E L LAST (X (X) ELAST)) .
So it is noteworthy that metacomposition enables us to represent the function "last" without
the use of any added environment-maintaining mechanism.
However, the defining equation for "last" is an example of a particularly simple class of
recursive forms -- the so called "tail recursions", and it remains to be shown that the existence
of the F F P object < L A S T > is not just due to some special properties of tail-reeursive
equations, but rather that atl F P functions can be so represented in FFP.
In this note we give a general algorithm for producing F F P representatives for arbitrary,
reeursively defined FP functions. In doing so, we will have demonstrated the universality of
FFP, since all partial recursive functions can be defined in FP. (That all primitive recursive
functions can be defined is clear. The min operator ~x:R(x) of [KL 52] can be realized by
the defined function
Def least = R -~ id; least o + o [id, i ]
since then /zx:R(x) = leastoO .) We will first give the algorithm for functions defined by a
single equation and then generalize it to include functions defined b y sets of mutually recursive equations.
Functions defined by a single equation
In order to show that every function definable in the informal FP system can be represented in FFP, we must g~ve some representation-producing mechanism ,r that maps the
domain F of expressions denoting functions in FP into the domain of F F P expressions such
that
VfinF,
p(*~O) = f
.
Note that qr will be a purely syntactic mapping from expressions in FP to expressions in FFP.
Now there are three types of functions in the FP system:
1) primitives P,
2) the closure of P under the combining forms, and
3) functions defined by (recursive) functional equations.
For functions of type 1) and 2) we will define
Backus chose in [Ba 78]. For example,
~r(tl)
~r(1)
~r(nullotl)
qr([id, atl])
~r(~)
etc.
-=
=
-=
~r to be consistent with the representation
TAIL
1
< C O M P , NULL, T A I L >
< C O N S , ID, < A L P H A , T A I L > >
<CONST, 3>
462
We will make one modification to the representation of [Ba 78]. Since the sequence
constructor of FFP is i-preserving, we cannot use < C O N S T , x > to represent x for all
objects x. Notice that while the object < C O N S T , ± > will correctly represent the function
T, a function such as
zerofilter = eq0 -,. id;
is not correctly represented by the FFP object
< C O N D , EQ0, ID, < C O N S T , ± > >
since the presence of l reduces that object to
U N D E F to represent the FP function -~.
±.
In this paper we will use the object
For functions defined by a recursive equation we define ,r as follows:
Definition If f = E f is a recursively defined FP function, where E is built up by applying
combining forms to primitive functions and the function letter f, then ~r(f) is defined
to be the FFP object <~rf(Ef)> where ~rf(Ef) is the FFP object that results from
applying the following representation-producing algorithm ~rf to the form Ef.
In describing this algorithm we will use a shorthand notation to clarify the exposition.
Since we know that all primitives and their closures under the combining forms have representing expressions in FFP, we will frequently use a more readable FP-like notation to denote
those FFP representations. For example, instead of < C O M P , TAIL, 2> we will write tlo2,
and instead of < C O M P , APPLY, < C O N S , 1, 2 > > we will write APPLYo[1, 2].
Algorithm (Representation-producing) The FFP representation of a form E f with respect to
the function letter f, *rf(Ef), is constructed recursivety by cases on the structure of Ef:
Form of E_f
FF..__P.Prepresentation of E_f
p (p in P)
po2
f
APPLY
x if x # ±, else U N D E F
--~ ,rf(Qf); ,rf(RjO
P f - " Of; R f
*rf(Pf)
[Pf, Qf]
[rrf(Pf), ~f(Qf)]
Pfo O f
~rf(Pf) o [1, *rf(Qf)]
a(Pf)
a(trf(Pf)) o distl
To illustrate the use of this algorithm, recall the definition
Def last = null otl -* 1 ; last o tl
Then the FFP object representing last is < L A S T >
where
463
LAST
=
*rlast(E(last))
=
*rlast(nullotl -~ 1; lastotl)
=
,tlast(nullotl ) -~ *rlast(1); ~last(last°tl)
=
~rlast(null) o [1, ~tlast(tl)] -~ *Zlast(1); ~'last(last o tl)
=
(hullo 2) o [1, tl o 2] -~ 1 o 2; ~last(last) o [1, ~last(tl)]
= n u l l o 2 o [ 1 , tlo2] -~ l o 2 ; A P P L Y o [ 1 , tlo2]
=
n u l l o t l o 2 -~ 1 o2; A P P L Y o [ 1 , t l o 2 ] , since d e f i n e d o 2 = > defined° 1,
which is exactly the expression chosen by Backus in [Ba 78].
To prove that < , r f ( E f ) >
always correctly represents the function f defined by
Def f -- Ef
we must show that
p(<~f(Ef)>)
=
f ,
i.e. t h a t for all objects x
#(<,rf(Ef)>:x)
-- f:x
or equivalently (according to the definition of metacomposition) that
#(*rf(Ef):<<*rf(Ef)>, x > )
Theorem.
= f:x .
If f is the FP function defined by Def f = Ef, then p ( < ~ f ( E f ) > )
= f.
Proof: We wilt show for all objects x and F P expressions Hf (i.e. functions built up from
the primitives and the function f by the application of combining forms) that
(1)
#(~f(Hf):<<~rf(Ef)>, x>)
=
Hf:x
and therefore, a fortiori, that
#(~f(Ef):<<~f(Ef)>,x>)
= Ef:x -- f:x .
Note that when x = ±, (1) holds trivially, since all functions are strict and the sequence
constructor is l-preserving. F o r x # ±, we will prove (1) by computational induction on the
length of the sequence of reductions (Hf:x -~ ... -~ y) that transforms the F P application
Hf:x into its meaning y. We will use.the inductive hypothesis:
(2) If Hf:x -~ y in less t h a n or equal to i steps, then # ( * r f ( H f ) : < < , r f ( E f ) > , x > )
= y.
By a step we m e a n one of the simplifications given by Backus in his informal description
of the semantics of FP systems [Ba78]. For example, the application of a primitive to an
464
object (.p:x -, y) and the substitution of a definition for a defined function name (f:x * Ef:x)
ace each considered to be one step in a reduction sequence. The n u m b e r of steps in the
sequence ((Pf ~- Qf; Rf):x -~ . . . . y) will be the n u m b e r of steps to evaluate Pf:x plus the
n u m b e r to evaluate whichever b r a n c h of the conditional is subsequently taken, Qf:x or R f : x .
Basis, i = t : If Hf:x -* y in one step, then there are two possible cases to consider:
(Note: In treating these cases it will be important to distinguish between FP and F F P
expressions. At the same time, for ease of reading we will continue to use the FP-like
abbreviations for F F P expressions. No confusion will arise if we r e m e m b e r that ~rf
maps FP expressions to F F P expressions and that the domain of # is F F P expressions. To help clarify these notational conventions, in the proof of the first case we
will show parenthetically the equivalent, unabbreviated forms of the F F P expressions
being used.)
Case BI:
Hf -- p (where p is some primitive), and p : x -~ y .
t~(~rf(Hf):< < ~ f ( E f ) > , x > )
= ~(,rf(p):<<~rf(Ef)>, x>)
= #(.po 2 : < < ~ r f ( E f ) > , x > ) , (i.e. ~ ( < C O M P , P , 2 > : < < ~ r f ( E f ) > , x > ) , where o ( P ) = p )
~(p:x), (i.e. ~(P:x) ), since < , r f ( E f ) > # ±
=
= p:x
~ since o ( P ) = P
=y.
CaseB2:
Hf = , / , a n d
~5:x-,.y.
~(~rf(Hf):< <~rf(Ef)>, x > )
= b~(Irf@):<<~f(Ef)>, x > )
= ~@:<<~f(Ef)>, x>)
= ~:x , since <~rf(Ef)> # ±
=y.
Induction step:
CaseIl.
Suppose that Hf:x -~ y in < i + l steps.
Hf = f , a n d
f:x-*y
in < i + l steps. Then Ef:x - ~ y in < i s t e p s , s o b y (2)
~(*rf(Ef):<<~rf(Ef):>, x > ) = y .
Therefore, a ( , r f ( H f ) : < < ~ r f ( E f ) > , x > )
= ~0rf(f):<<~rf(Ef)>, x>)
= ~ ( A P P L Y : < <~rf(Ef)>, x > )
= ~(<~f(Ef)>:x)
465
= #(*rf(Ef):<<*rf(Ef)>, x > )
--~y.
Case 12. Hf = [If, Jr] , and [If, Jf]:x -~ y in < i + 1 steps. Then
If:x -~ Yl in < i steps
and J f : x * Y 2 in < i s t e p s ,
where y --= <Yl, Y2> , so that
/~(~rf(If):<<*rf(Ef)>, X>) -- Yl
and /~(,rf(Jf):<<,rf(Ef)>, x > ) - Y2 •
Therefore,/~0rf(Hf):<<*rf(Ef)>, x>)
= ~t(~rf([If, J f ] ) : < < * r f ( E f ) > , x > )
-- /~([~rf(If), ~rf(Jf)]:<<~rf(Ef)>, x > )
-- </t(~rf(If):<<rrf(E,f)>, x > ) , /~(*rf(Jf):<<~rf(Ef)>, x > ) >
= < Y l , Y2 >
=y.
Case I3. Hf = Pf-*- Q f ; R f , and ( P f - ~ Q f ; R f ) : x - ~ y
in < i + 1 steps.
similar to Case I2.
Case I4. Hf = I f o J f , and I f o J f : x -~ y in _< i + 1 steps. Then ~ such that
Jf:x - ~ z in < i s t e p s
and I f : z - ~ y in_< i s t e p s ,
so that
/z(rrf(Jf):<<,rf(Ef)>, x > ) = 2
and # ( r r f ( I f ) : < < * r f ( E f ) > , z > ) -- y .
Therefore,/t(*rf(Hf):<<~rf(Ef)>, x>)
ff(qrf(If o Jf): < < ~rf(Ef) > , x > )
#(*rf(If) o [1, ~rf(Jf)]:<<~rf(Ef)>, x > )
#(*rf(If):<<~rf(Ef)>,/~(rrf(Jf):<<qrf(Ef)>, x > ) > )
/t(*rf(lf) : < <*rf(Ef)>, z > )
=y.
Case I5. H f = a ( P f ) , and a ( P f ) : < X l . . . . .
Xn> -~ <YI, "'" ,Yn >
in < i + 1 steps. T h e n
466
Pf:xi "~Yi in _< / s t e p s , (l_<j_<n),
so t h a t
# ( * r f ( P f ) : < < ~ r f ( E f ) > , x j > ) = yj, (1 < j < n ) .
Therefore, #(~rf(Hf):<<~rf(Ef)>, x>)
= #(qrf(a(Pf)):<<*rf(Ef)>, x>)
= ~(a(*rf(Pf)) o DISTL: < < ~rf(Ef) > , x > )
= /*(a(*rf(Pf)):<<<~rf(Ef)>, Xl> .....
<<~rf(Ef)>, Xn>> )
= < / ~ ( * r f ( P f ) : < < * r f ( E f ) > , X l > ) . . . . . ~t(~rf(Pf):<<qrf(Ef)>, X n > ) >
= <Yl . . . . . Yn >
= y.
QED
T h u s we k n o w t h a t e v e n very complex f u n c t i o n s can be r e p r e s e n t e d in t h e F F P notation.
F o r example, the n o n - p r i m i t i v e - r e c u r s i v e " A c k e r m a n n f u n c t i o n " d e f i n e d b y
D e f ack = e q 0 o l
(where
<ACK>
a
-,. a o 2 ; e q 0 o 2 -- a c k o [ s o 1, T]; a c k o [ s o l ,
acko[1, so2]]
a n d s are primitives that, respectively, add a n d s u b t r a c t 1) is r e p r e s e n t e d by
where, a c c o r d i n g to t h e algorithm,
ACK
= qraek(E(ack))
= *rack(eq0 o I -*- a o 2 ; e q 0 o 2 -~ a c k o [ s o 1, ]-]; a c k o [ s o 1, a c k o [ 1 , s o 2 ] ] )
= ~ack(eq0o 1) -* ~-ack(ao2); qrack(eq0°2) -*- ,rack(aCko[so 1 , -1"]);
*rack(ack o [s o 1, ack o [ 1, s o 2]]))
= e q 0 o 1 0 2 -~ a o 2 o 2 ; e q 0 o 2 o 2 --. ,rack(aCko[so 1, i ] ) ;
,raek(aCk o [s o 1, ack o [ 1, s o 2]])
= eq0 o 1 ° 2 -~ a o 2 o 2 ; e q 0 o 2 o 2 * A P P L Y o [ 1 , [so 1 0 2 , I ] ] ;
A P P L Y o [1, [s o 1 o 2, A P P L Y o [1, [1 o 2, s o 2 o 2]]]]
Functions defined by mutually reeursive equations
C o n s i d e r n o w a collection of f u n c t i o n s d e f i n e d b y a set of mutually recursive e q u a t i o n s
such as
f --. F f g h
g -- G f g h
h = Hfgh
467
We might try to extend the above approach by iterating the algorithm with respect to the
various function letters being defined; i.e. we might try letting
h' = ~rh(Hfgh),
Grfg = Gfgh with <h~> substituted for h ,
g' = ~rg(Grfg),
F~f = Ffgh with < h t > substituted for h and <gP> substituted for g ,
jd = ~rf(Ftf),
and <f~> = the representation for f.
However, this fails since Grfg is an object that contains an FFP expression and therefore is
not in the domain of definition of *rg, a mapping that takes FP objects as input. Nor can the
definition of ~rg be extended to include F F P objects. Essentially the difficulty is that
determining whether an arbitrary occurrence of an atom A in an F F P object represents a
function to be applied or simply the object A is recursively unsolvable.
However, if we modify the algorithm to produce representations with respect to all of the
defined functions simultaneously, then it is possible to construct correct representations for FP
functions defined by mutually recursive equations. The idea is that if Hfgh (some form using
the defined functions f, g, and h) is being applied to an object x in FP, then in F F P the object
representing Hfgh wilt be applied to a pair <ENV, x>, where ENV is a sequence that
contains the representations of all of the functions defined by functional equations. Intuitively, ENV will comprise the "environment" of currently defined functions.
Suppose now that we have a collection of mutually recursive definitions, one of which
(say Def f = Ffgh ) defines the function f. We need to choose a representation for f, i.e.
to define ,r(f), such that the application
~r(f):x
will result in the application
,r(Ffgh ): <ENV, x>
where ENV somehow contains the representations for all of the functions f, g, and h. One
way to accomplish this is to let f , gr, and h r be the representations of Ffgh, Gfgh, and Hfgh
respectively, and to let
and
< f , iv, gt, h ' > represent f,
<gl, f,, gl, hi> represent g,
<h r, ja, g , hr> represent h.
(We will see that this slightly redundant representation -- having two occurrences of the
function being defined -- will make the extension of the representation-producing algorithm
simpler and more uniform.)
Note now that
~(~:x)
468
= ~(</,/,
= ~:<<f',
J, h'>:x)
f', g', h'>, x>~
= ~ ( ~ r ( F f g h ) : < < / , / , g', h'>, x > )
= ~(~r(Ffgh): <ENV, x>)
where ENV is taken to be the sequence whose ( i + 1 ) st element is the representation of the ith
defined function and whose first element is any arbitrary F F P object.
All that remains is to develop the extended algorithm so that the meaning of ~r(Ffgh)
applied to the pair <ENV, x> in F F P will be the same as the meaning of Ffgh:x in FP.
We will use ~rD to denote this extended algorithm, since the algorithm will be used to
produce representations of FP forms with respect to a set D of defined function symbols.
Algorithm (Extended representation-producing) If D is an ordered set of n atoms denoting
defined function names, then the F F P representation of a form E with respect to the set D,
~rD(E), is constructed recursively by cases on the structure of E:
Form of E
FFP representation of E
p (an atom not in D)
po2
fi (the i th element of D)
APPLYo [[i, 1, 2 ..... n ] o T A I L o 1, 2]
if x ~ ±, else U N D E F
P.~, Q; R
~rD(P ) -~ ~rD(Q) ; ~D(R)
ie, Q]
f~rD(e), ~rD(Q)]
poQ
0rD(P) o [1, ~rD(Q)]
~(t")
ct(~rD(p) ) o DISTL
(Note that ~D is just the same as vf except for the case E = fi')
Then given a set of definitions for the n functions f = {-/'1 .....
fn}:
Def f l = E l f
Def /'2 = E2f
Def f n = Enf
we will choose for
sequence
fr(fi) (the FFP representation of the function
< F i, F 1, F 2, ... , F n >
where
F i = ~rD(Eif) for ]<i<_n.
fi)
the ( n + l ) - e l e m e n t
469
To show that these objects correctly represent the defined functions, we need to show for
all objects x and FP expressions Hf (i.e. functions built up from the primitives and the
functions fi by the application of combining forms) that
#(~rf(Hf):<ENV, x > ) = H f : x .
This can be shown by using the proof of the theorem for the single equation algorithm given
above with case I1 modified as follows:
Case I1 r. Hf -- f i , and fi:x "*" Y in _< i+1 steps. Then
Eif:x -~ y in _< i steps,
so that
#(WD(Eif):<ENV, x>) = y .
Therefore, #(~rD(Hf): < E N V , x > )
= Iz(*rD(fi):<ENV, x > )
= #(~rD(fi):<<Obj, F 1, F2, ... , Fn>, x > )
, for some object Obj
= #(APPLYo [[i, 1, 2 ..... n ] o T A I L o 1, 2 ] : < < O b j , F1, F 2 . . . . . Fn>, x > )
= / ~ ( A P P L Y : < < F i, E l, F 2 . . . . . Fn>, x > )
= #(<Fi, F 1, F 2. . . . . Fn>:X)
-- # ( F i : < < F i , El, F 2. . . . . Fn>, x > )
= t~(~rD(Eif):<ENV, x > )
m y
.
Acknowledgments I am grateful to John Backus, Carl Hauser, Peter Lucas, Steven Muchnick,
and Donald Stanat, all of whom read earlier drafts of this paper and made many helpful
comments and suggestions. I am particularly indebted to Carl Hauser for suggesting the proof
technique used in the main theorem.
References
[Ba 78]
Backus, J.W. "Can programming be liberated from the von Neumann style? A
functional style and its algebra of programs." C A C M , August 1978.
[Ch 41]
Church, A. The Calculi o f Lambda-Conversion.
Princeton, N.J., 1941.
[Cu 58]
Curry, H.B. and Feys, R. Combinatory Logic, Vol. 1. North-Holland Pub. Co.,
Amsterdam, 1958.
Princeton University Press,
470
[i~ 52]
Kleene, S.C.
!952.
EMc 60]
McCarthy, J. HRecursive functions of symbolic expressions and their computation by machine, Part 1." CACM, April 1960.
Introduction to Metamathematics, Van Nostrand, New York,
© Copyright 2026 Paperzz