Scheme Local Definitions
When I introduced Scheme Functions previously I mentioned how you cannot declare constants in functions. You can only declare constants in a global scope. This has not changed but here we present a method that appears to allow you to define constants in a function as well as nested functions. To accomplish this we use a local definition.
One use for this is to clean up functions by giving values a more symbolic name.
Example of writing a function using local constants:
(define (calc x) (local [(define y 4)] (+ y 4)))
In the square brackets within the local statement is where we include all our constant and function definitions. When the code is complied all local definitions are lifted out to the global scope. So this code is treated as:
(define y_0 4) (define (calc x) (+ y_0 x))
Each local value gets appended with a number that has not been used previously. Once the function that had the local terminates the constants go out of scope and are no longer usable.
(define (calc x) (local [(define (f y) (cond [(zero? y) x] [(even? y) (* x y)] [else (+ x y)]))] (f x)))
The function f only has scope to all variables in f and all parameters of calc. Once the function f produces a value all it’s parameters are not accessible anymore. Also: calc does not have access to the parameters defined in f or any of f’s constants.
This is useful when you need to isolate a block of code in a function but you only want the function that needs it to have access to the code. Later we will see that functions can be used to simulate structures. This makes heavy use of local and a topic that is crucial but has not yet been interested: lambda functions.
The main use of local, however, is to make code more readable by naming values used and to limit scope of variables to the level in which they need to be visible.
We can have local definitions nested within each other. For example:
(define (f x) (local [(define (g y) (local [(define (h z) (+ z y))] (h y)))] (g x)))
Here we have a local nested within a local. This is a great opportunity to introduce scope. The inner function (h x) has access to all variables given to it as parameters and all constants defined in a local in it’s body. It also has access to all variables introduced before h is defined. So h is the innermost function has access to the values z, x and y. The function g, however, only has access to x and y.
This allows us to have nested functions. The problem with this is it is extremely ugly. We will look at another way to do this later that will clean it up a little. We have all sorts of square brackets around and all sorts of parenthesis that are really hard to match up with their opening bracket. So if a parentheses is misplaced then it will be really hard to find where this error is.
One more thing to note is if we write a function like this:
(define (f x) (local [(define (g x) (+ x x))] (g 3)))
The x defined in g’s scope will hide the x given to f. Meaning f will always produce the value 6 regardless of what value is given to x as a parameter.