繁体   English   中英

“参数化”在DrScheme中做了什么?

[英]What does 'parametrize' do in DrScheme?

我试图理解这里的示例代码(下面的例子)。 我不明白参数化构造。 它的文档在这里 ,但它们没有帮助。 它有什么作用?

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使用fluid-let )是使用dynamic-wind保护参数的保存/恢复,这样可以确保如果出现错误(如果你知道延续的话,还有更多),那么值仍然是恢复。

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

另一个问题更微妙。 假设您有一个带有数值的参数,并且您想要执行以下操作:

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

在Scheme中,“尾调用”很重要 - 它们是创建循环的基本工具等等。 parameterize化做了一些魔术,允许它暂时更改参数值,但仍保留这些尾调用。 例如,在上面的例子中,你得到一个无限循环,而不是得到一个堆栈溢出错误 - 会发生什么是这些parameterize表达式中的每一个都能以某种方式检测何时有一个不再需要进行清理的早期parameterize

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

parameterize将特定parameterize设置为块的持续时间的指定值,而不影响它们之外的值。

参数化是一种可以动态重新绑定现有函数中的值的方法,而不使用lambda来实现。 在实践中,有时使用参数化来重新绑定函数中的值而不是传递参数并使用lambda绑定它们要容易得多。

例如,假设您使用的库将HTML发送到stdout,但为了方便起见,您希望将该值捕获到字符串并对其执行进一步操作。 库设计者至少有两种选择可以让您轻松:1)接受输出端口作为函数的参数或2)参数化current-output-port值。 1是丑陋和麻烦。 2更好,因为最可能的行为是打印到stdout,但是如果你想打印到字符串端口,你可以参数化对该函数的调用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM