I'm in a Scheme class and I was curious about writing a recursive function without using define. The main problem, of course, is that you cannot call a function within itself if it doesn't have a name.
I did find this example: It's a factorial generator using only lambda.
((lambda (x) (x x))
(lambda (fact-gen)
(lambda (n)
(if (zero? n)
1
(* n ((fact-gen fact-gen) (sub1 n)))))))
But I can't even make sense of the first call, (lambda (x) (x x)): What exactly does that do? And where do you input the value you want to get the factorial of?
This is not for the class, this is just out of curiosity.
Basically what you have is a form similar to the Y combinator. If you refactored out the factorial specific code so that any recursive function could be implemented, then the remaining code would be the Y combinator.
I have gone through these steps myself for better understanding.
https://gist.github.com/z5h/238891
If you don't like what I've written, just do some googleing for Y Combinator (the function).
The expression
(lambda (x) (x x))
creates a function that, when evaluated with one argument (which must be a function), applies that function with itself as an argument.Your given expression evaluates to a function that takes one numeric argument and returns the factorial of that argument. To try it:
There are several layers in your example, it's worthwhile to work through step by step and carefully examine what each does.
A little off-topic here, but seeing the above statements I just wanted to let you know that "without using define" does not mean "doesn't have a name". It is possible to give something a name and use it recursively in Scheme without define.
It would be more clear if your question specifically says "anonymous recursion".
I like this question. 'The scheme programming language' is a good book. My idea is from Chapter 2 of that book.
First, we know this:
With
letrec
we can make functions recursively. And we see when we call(fact 5)
,fact
is already bound to a function. If we have another function, we can call it this way(another fact 5)
, and nowanother
is called binary function (my English is not good, sorry). We can defineanother
as this:Why not we define
fact
this way?If
fact
is a binary function, then it can be called with a functionf
and integern
, in which case functionf
happens to befact
itself.If you got all the above, you could write Y combinator now, making a substitution of
let
withlambda
.(lambda (x) (x x))
is a function that calls an argument, x, on itself.The whole block of code you posted results in a function of one argument. You could call it like this:
That calls it with 5, and returns 120.
The easiest way to think about this at a high level is that the first function,
(lambda (x) (x x))
, is giving x a reference to itself so now x can refer to itself, and hence recurse.(lambda (x) (x x))
takes a function object, then invokes that object using one argument, the function object itself.This is then called with another function, which takes that function object under the parameter name
fact-gen
. It returns a lambda that takes the actual argument,n
. This is how the((fact-gen fact-gen) (sub1 n))
works.You should read the sample chapter (Chapter 9) from The Little Schemer if you can follow it. It discusses how to build functions of this type, and ultimately extracting this pattern out into the Y combinator (which can be used to provide recursion in general).