An Introduction to the Y Combinator
Recursive Procedures Without letrec
!
The Why of Y
Some of you have expressed interest in the more advanced uses of Racket and functional programming. If you are one of those people, read on. If not, feel free to return from whence you came.
In a reading about
local recursive functions,
I asked if you could give a translational semantics for
letrec
using lambda
, and I hinted that
you would have to do something we have never done before in
Racket. That something is to change an existing variable binding
— that is, to use a assignment statement!
Actually, there is a way to implement recursive procedures without
using letrec
or any language primitives beyond what
we already know. This technique relies only on the ability to
pass a function as an argument to another function. It creates a
special kind of combinator, which is a lambda
expression without any free variables. We encountered the idea of
a combinator briefly in
Session 12.
The Y combinator is one of the cool theoretical achievements in programming language theory. It shows that it is possible to create even a recursive function without a name. But how can a function call itself if it doesn't have a name? The trick: by passing itself to itself. This technique works even in a language that does not support recursive functions directly, as long as it support higher-order functions.
What is the Y combinator? How can it work? Here are two options for you:
- Check out this short derivation by Prof. John Franco at the University of Cincinnati. It is relatively gentle and aimed at college students. (This is a local copy of Franco's original page, which seems to have disappeared from the web.)
- If you would like to dive deeper, read Richard Gabriel's essay, The Why of Y. If you want to play along with Gabriel's ideas in Dr. Racket, feel free to use this source file that contains code from the paper.
Be forewarned: In order to derive Y, both authors have to work
through several layers of higher-order functions, repeatedly
abstracting lambda
expressions out of
lambda
expressions. The process makes my head spin!
It may do the same to you.
Even so, do not think that the Y combinator works only in Racket or a Lisp-like language. Any language with higher-order functions will do. You can check out versions of the Y combinator in:
- Python,
- Javascript,
- Ruby,
- and even Perl (down the page three-fourths of the way).
I think some of these implementations are quite beautiful, perhaps most surprisingly the Perl version!
This zip file contains code files for these four implementations of Y, along with the Racket version mentioned above.
Acknowledgments
My copy of Gabriel's paper mirrors
his original,
which can be found on his web site,
www.dreamsongs.com
.
Richard is not only an expert in several areas of computer
science, including object-oriented programming, programming
languages, and AI. He is also a working poet.