Unbound Variables in Racket

This section is for fun.
See if you can follow the argument.
Don't worry; I won't ask you to do gymnastics like this on the quiz!

Let's try a bit of Racket mental gymnastics. Can you create an expression that:

Can you create an expression that:
  1. doesn't use a conditional,
  2. contains an unbound variable, and
  3. whose value is not affected by the value of the unbound variable?
Hint: how can 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:

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.