Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Racket and unbound identifier in lambda expression, contrast with r5rs

In DrRacket, when I set the language to R5RS and run the following code:

(lambda (x) z)

it runs without error and returns #<procedure>. This makes sense to me; the lambda form defines a procedure whose body has not yet been evaluated, and so that procedure is returned.

Alternatively, when I use the Racket language dialect, I get the following error:

z: unbound identifier in module in: z

I don't understand why Racket is producing this error. I mean, of course I see that z is undefined, but my understanding of the evaluation model is that the body of the function is not evaluated at the time of the function definition. That's consistent with the R5RS result, but not with the Racket result. What is Racket doing here, precisely? Is it "peeking" in some way in the body of the code to see if the variables are defined? What is different in the evaluation model from R5RS that results in this different behavior?

like image 512
Vultan Avatar asked Dec 24 '22 21:12

Vultan


2 Answers

A #lang file is module. The specification of how modules are expanded and evaluated are in the described in detail in the documentation. After some digging I found this note:

No identifier can be imported or defined more than once at any phase level within a single module. Every exported identifier must be imported or defined. No expression can refer to a top-level variable.

The last sentence "No expression can refer to a top-level variable." means that all variables must be bound.

In contrast an expression entered in the repl is not a module, but an expression "outside" any modules. A reference to an unbound variable becomes a reference to a top-level variable. When the expression is evaluated the value of the top-level variable will be looked up in the current namespace. If at the time of the lookup, the variable has no associated value, an error will be signaled.

The repl uses this convoluted rule in order to allow definitions of mutual recursive functions, one define at a time.

For more information on the REPL, see: https://gist.github.com/samth/3083053

like image 79
soegaard Avatar answered Dec 31 '22 14:12

soegaard


Source file in Racket

#lang racket
(define f (lambda (x) z))

Result:

z: unbound identifier in module in: z

REPL interaction:

Welcome to DrRacket, version 6.1.1 [3m].
Language: racket; memory limit: 128 MB.
> (define f (lambda (x) z))
> 

No error.

Source file with z defined:

#lang racket
(define f (lambda (x) z))
(define z 5)

No error.

So, Racket ensures that all variables in the source file are defined, without making the same guarantee about REPL code. I can only see this as a good thing, as it prevents errors in source files.

like image 20
WolfeFan Avatar answered Dec 31 '22 13:12

WolfeFan