parameterize used to have values that are "dynamically constrained". You get the make-parameter . The parameter itself behaves like a function: calls it without inputs, and you get its value, call it with one value and set the value. For example:
> (define p (make-parameter "blah")) > (p) "blah" > (p "meh") > (p) "meh"
Many functions (including many primitive ones) use parameters as a way to customize their behavior. For example, printf will print material using the port, which is the value of the current-output-port parameter. Now say that you have a function that prints something:
> (define (foo x) (printf "the value of x is ~s\n"))
Usually you call this function and see something printed on the screen, but in some cases you want to use it to print something in a file or something else. You can do it:
(define (bar) (let ([old-stdout (current-output-port)]) (current-output-port my-own-port) (foo some-value) (current-output-port old-stdout)))
One problem is that it is tedious - but it is easy to solve with a macro. (Actually, PLT still has a construct that does this in some languages: fluid-let .) But there are more problems here: what happens if foo invokes a runtime error? This can cause the system to be in a bad state, where all the output goes to your port (and you won’t even see a problem, since it doesn’t print anything). The solution for this (which is also used by fluid-let ) is to protect the save / restore parameter with dynamic-wind , which ensures that if there is an error (and much more if you know about the continuations), then the value is restored anyway.
So the question is, what is the point with the parameters instead of just using global variables and fluid-let ? There are two more problems that you cannot solve only with global variables. One of them is what happens when you have multiple threads - in this case, setting the value temporarily affects other threads that can still print to standard output. Parameters solve this by having a specific value for the stream. It happens that each thread "inherits" the value from the thread that created it, and changes in one thread are visible only in that thread.
Another problem is more subtle. Say you have a parameter with a numeric value, and you want to do the following:
(define (foo) (parameterize ([p ...whatever...]) (foo)))
Tail calls are important in the circuit - they are the main tool for creating loops and much more. parameterize performs some magic that allows you to temporarily change the value of a parameter, but at the same time save these tail calls. For example, in the above case, you will get an infinite loop and not get an error - what happens is that each of these parameterize expressions can somehow detect when there is an earlier parameterize that no longer needs to be cleaned up.
Finally, parameterize actually uses two important parts of the PLT to do its job: it uses stream cells to implement values for each stream and uses continuation labels to store tail calls. Each of these features is useful in its own right.