Unbound Variables in Racket
Let's try a bit of Racket mental gymnastics. Can you create an expression that:
- doesn't use a conditional,
- contains an unbound variable, and
- whose value is not affected by the value of the unbound variable?
lambda help?
We could try a lambda expression:
(lambda (x) y)
y is unbound—but if no one ever applies the
lambda expression to an argument, then
y will never be evaluated!
But if someone does apply the lambda to an
argument, the interpreter will evaluate the y.
So the value of applying the lambda depends on
the value of y. That's another wrinkle. Can we
iron it out?
Here is a hint: Suppose I have a function that makes no use of its formal parameter. That is, its value is independent of the value of any argument that is passed to it. Here is an example:
(lambda (x) (lambda (y) y))
This function takes some value, binds it to x, and
then ignores x, returning a lambda
expression that doesn't refer to it.
Can you use this idea to create an expression that contains a free variable and whose value doesn't depend on the value of that variable? How about this example?
( (lambda (x)
(lambda (y) y))
x )
The value of this expression doesn't depend on the value of
x! Alas, unlike the if expression and
first lambda expression above, the Racket interpreter
will evaluate the x — in order to pass
it as an argument. This does, however, show us that the value of
an expression can be independent of the value of a free variable
it contains. That is a step forward.
Now we know what we have to do: write a function that:
- takes an argument containing a free variable that is never evaluated, and
- never evaluates its argument.
If we pass a lambda expression that contains a
free variable, the variable won't be evaluated until the
lambda is applied. But if the receiving function
never uses its argument, the free variable will never be
evaluated!
So:
> ( (lambda (x)
(lambda (z) z))
(lambda (x) y) )
#<procedure>
The y in the function passed as an argument is
free, but never evaluated. We can apply this function to any
argument:
> (((lambda (x)
(lambda (z) z))
(lambda (x) foo))
'x)
'x
Yes, this is only an academic exercise. You won't ever need such a function, certainly not in this course. Dr. Racket won't even let you do it in source code! But it's a useful little puzzle to help us explore and understand better the idea of free and bound variables.
Sometimes, computer scientists like to play fun little games that other people might not see as fun! I hope you at least find it instructive.