-
Notifications
You must be signed in to change notification settings - Fork 21
/
04.13 动态绑定:parameterize
88 lines (58 loc) · 3.11 KB
/
04.13 动态绑定:parameterize
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
4.13 动态绑定:parameterize
parameterize表把一个新值和body表达式求值过程中的一个参数(parameter)相结合:
(parameterize ([parameter-expr value-expr] ...)
body ...+)
例如,error-print-width参数控制在错误消息中打印一个值的字符数:
> (parameterize ([error-print-width 5])
(car (expt 10 1024)))
car: contract violation
expected: pair?
given: 10...
> (parameterize ([error-print-width 10])
(car (expt 10 1024)))
car: contract violation
expected: pair?
given: 1000000..
一般来说,参数实现了一种动态绑定。make-parameter函数接受任何值并返回一个初始化为给定值的新参数。应用参数作为一个函数返回它的其当前值:
> (define location (make-parameter "here"))
> (location)
"here"
parameterize表不是一个像let那样的绑定表;每次location的使用向上都直接指向原来的定义。在parameterize主体被求值的整个时间内parameterize表调整参数的值,甚至是文本以外的parameterize主体的参数使用:
> (define (would-you-could-you?)
(and (not (equal? (location) "here"))
(not (equal? (location) "there"))))
> (would-you-could-you?)
#f
> (parameterize ([location "on a bus"])
(would-you-could-you?))
#t
如果参数的使用是在parameterize主体内部进行的,但是在parameterize表产生一个值之前没有被求值,那么这个用法看不到parameterize表所安装的值:
> (let ([get (parameterize ([location "with a fox"])
(lambda () (location)))])
(get))
"here"
参数的当前绑定可以通过将该参数作为具有值的函数进行调用以进行必要的调整。 如果parameterize已经调整了参数的值,那么直接应用参数过程只会影响与活动parameterize相关的值:
> (define (try-again! where)
(location where))
> (location)
"here"
> (parameterize ([location "on a train"])
(list (location)
(begin (try-again! "in a boat")
(location))))
'("on a train" "in a boat")
> (location)
"here"
使用parameterize通常更适合于更新参数值,这与使用let绑定新变量的原因相同,最好使用set!(见《赋值:set!》)。
似乎变量和set!可以解决很多参数解决的相同问题。 例如,lokation可以被定义为一个字符串,以及set!可以用来调整它的价值:
> (define lokation "here")
> (define (would-ya-could-ya?)
(and (not (equal? lokation "here"))
(not (equal? lokation "there"))))
> (set! lokation "on a bus")
> (would-ya-could-ya?)
#t
然而,参数与set!相比,参数提供了几个关键的优点:
1、parameterize表有助于在正确避免异常时自动重置参数的值。 添加异常处理程序和其它表去实现转回一个set!是比较繁琐的。
2、参数可以和tail调用很好的一致(请参阅《尾递归》)(Tail Recursion)。 parameterize表中的最后一个body相对于parameterize表处于尾部位置。
3、参数与线程正常工作(请参阅《线程》)(Threads)。 parameterize表仅调整当前线程中的参数值,以避免与其他线程竞争。