What does "parameterization" do in DrScheme?

I am trying to understand the sample code here (Examples below). I do not understand what design to parameterize . The docs for this are here , but they do not help. What is he doing?

+6
functional-programming scheme racket
source share
3 answers

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.

+13
source share

parameterize sets certain parameters for the given values ​​for the duration of the block, without affecting their values ​​outside it.

+3
source share

Parameterization is a means by which you can dynamically bind values ​​within an existing function without using lambda to do this. In practice, it is sometimes much easier to use parameterization to re-bind values ​​inside a function, rather than passing arguments and binding them using lambdas.

For example, let's say that the library you are using produces HTML in stdout, but for convenience you want to write this value to a string and perform further operations on it. The library developer has at least two options to make this easy: 1) accept the output port as an argument to the function, or 2) parameterize the value of the current-output port. 1 is ugly and hassle. 2 is better, since the most likely behavior is to print to stdout, but if you want to print to a string port, you can simply parameterize the call to this function.

+3
source share

All Articles