2009-12-08 42 views
6

我试图理解示例代码here(下面的示例)。我不明白参数化构造。文档为here,但他们没有帮助。它有什么作用?DrScheme中的'parametrize'是做什么的?

+0

为什么使用tinyurl.com?在使用完整网址时没有严重的空间限制,缩略图使链接看起来更加可疑。 – 2009-12-08 22:34:56

+1

链接已末尾括号,这使得他们无法正常工作瓦特/加价,如此使用 – Claudiu 2009-12-09 00:04:05

+0

吉米尼圣诞节,这些链接甚至不会与引文,在底部降价的工作作风。 – Chuck 2009-12-09 01:22:37

回答

13

parameterize用于具有被“动态作用域”值。你得到一个参数make-parameter。参数本身表现为一个函数:在没有输入的情况下调用它,并获得它的值,用一个值调用它并设置该值。例如:

> (define p (make-parameter "blah")) 
> (p) 
"blah" 
> (p "meh") 
> (p) 
"meh" 

许多函数(包括许多基本函数)使用参数作为自定义其行为的一种方式。例如,printf将使用current-output-port参数值的端口打印内容。现在,假设你有一些功能,打印的东西:

> (define (foo x) (printf "the value of x is ~s\n")) 

通常你调用这个函数,看到印在屏幕上的东西 - 但在某些情况下,你想用它来打印一些文件或任何。你可以这样做:

(define (bar) 
    (let ([old-stdout (current-output-port)]) 
    (current-output-port my-own-port) 
    (foo some-value) 
    (current-output-port old-stdout))) 

这样做的一个问题是它很繁琐 - 但这很容易用宏解决。 (实际上,PLT仍然有一个在某些语言中使用的构造:fluid-let)。但是这里存在更多问题:如果调用foo会导致运行时错误,会发生什么情况?这可能会导致系统处于不良状态,所有输出都会传送到您的端口(并且您甚至不会看到问题,因为它不会打印任何内容)。用于该溶液(其中fluid-let使用过)是保护储蓄/与dynamic-wind参数的恢复,这可以确保如果有错误(多,如果你知道的延续),则该值仍然恢复。

所以,问题是什么是有参数,而不是仅仅使用全局和fluid-let点?还有两个问题是你无法用全局变量解决的。一种是当你有多个线程时会发生什么 - 在这种情况下,临时设置该值会影响其他线程,这些线程可能仍然要打印到标准输出。参数通过每个线程具有特定值来解决这个问题。会发生什么情况是,每个线程都从创建它的线程“继承”该值,并且一个线程中的更改仅在该线程中可见。

另一个问题更为微妙。说你有一个数值的参数,并且要做到以下几点:

(define (foo) 
    (parameterize ([p ...whatever...]) 
    (foo))) 

在计划,“尾调用”是很重要的 - 他们是创造循环和更多的基本工具。 parameterize做了一些神奇的事情,允许它暂时改变参数值,但仍保留这些尾部调用。例如,在上述情况下,你得到一个无限循环,而不是得到一个堆栈溢出错误 - 什么情况是,当有不再需要做一个较早parameterize这些parameterize表达式可以以某种方式检测其清理。

最后,parameterize实际上使用PLT的两个重要部分来完成它的工作:它使用线程单元来实现每个线程的值,并且它使用连续标记来保存尾部调用。这些功能本身都很有用。

+0

真棒答案 - 谢谢! – Claudiu 2009-12-09 17:17:21

3

parameterize设定特定参数,以用于所述块的持续时间指定的值,在不影响其外部它们的值。

+0

嗯有趣 – Claudiu 2009-12-09 00:04:46

3

参数化是通过它可以动态地重新绑定的现有函数内的值,而无需使用lambda这样做的装置。在实践中,有时使用参数化来重新绑定函数中的值比使用lambda来传递参数和绑定参数要容易得多。

例如,假设你使用一个库发出HTML到标准输出,但为方便起见,你要拍摄价值为字符串,并在其上执行进一步的操作。库设计人员至少有两种选择可以让您轻松实现:1)接受输出端口作为函数的参数或2)参数化当前输出端口值。 1是丑陋和麻烦。 2是更好的,因为最可能的行为是打印到标准输出,但是如果你想打印到一个字符串端口,你可以参数化该函数的调用。