4

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?

Vultan
  • 409
  • 3
  • 13
  • 1
    I don't get this behavior. At the top-level, outside of a module (or in the REPL), no error occurs in either language, while at the module-level, I get an unbound identifier error in both languages. How exactly are you testing this behavior? – Alexis King Apr 08 '15 at 16:58
  • 1
    The Racket case I'm doing via a #lang racket in the first line, setting DrRacket to "determine language from source," and clicking the Run button. In the second case, I _don't_ have #lang racket, and I set DrRacket via the drop box at the bottom to R5RS. Am I actually seeing module vs. non-module behavior? If so, can you elaborate on what's going on? – Vultan Apr 08 '15 at 17:11
  • I can confirm. I see the same issue when using `#lang racket`. In the repl with racket it does work however. – Christophe De Troyer Apr 08 '15 at 17:57

2 Answers2

5

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.

WolfeFan
  • 1,447
  • 7
  • 9
5

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

soegaard
  • 30,661
  • 4
  • 57
  • 106
  • 1
    Note that the behavior the OP is describing is caused by the fact that setting the language to R5RS from the Language menu evaluates the file at the top-level, instead of within a module with the `r5rs` module language. – Alexis King Apr 08 '15 at 22:49
  • Thanks for this answer -- it's at least pointing me in the right directions. I still don't claim to understand what Racket's evaluation model is in the case of a module, but I'm trying to read up on it. – Vultan Apr 09 '15 at 02:51