-
Notifications
You must be signed in to change notification settings - Fork 21
/
04.11 准引用:quasiquote和`
105 lines (77 loc) · 3.14 KB
/
04.11 准引用:quasiquote和`
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
4.11 准引用:quasiquote和`
quasiquote表类似于quote:
(quasiquote datum)
然而,对于出现在datum的每个(unquote expr),expr被求值并产生一个替代unquote子表的值。
例如:
> (quasiquote (1 2 (unquote (+ 1 2)) (unquote (- 5 1))))
'(1 2 3 4)
此表可用于编写根据特定模式生成列表的函数。
例如:
> (define (deep n)
(cond
[(zero? n) 0]
[else
(quasiquote ((unquote n) (unquote (deep (- n 1)))))]))
> (deep 8)
'(8 (7 (6 (5 (4 (3 (2 (1 0))))))))
甚至可以以编程方式廉价地构造表达式。(当然,第9次就超出了10,你应该使用一个macro来做这个(第10次是当你学习了一本像PLAI那样的教科书)。)
例如:
> (define (build-exp n)
(add-lets n (make-sum n)))
> (define (add-lets n body)
(cond
[(zero? n) body]
[else
(quasiquote
(let ([(unquote (n->var n)) (unquote n)])
(unquote (add-lets (- n 1) body))))]))
> (define (make-sum n)
(cond
[(= n 1) (n->var 1)]
[else
(quasiquote (+ (unquote (n->var n))
(unquote (make-sum (- n 1)))))]))
> (define (n->var n) (string->symbol (format "x~a" n)))
> (build-exp 3)
'(let ((x3 3)) (let ((x2 2)) (let ((x1 1)) (+ x3 (+ x2 x1)))))
unquote-splicing表和unquote相似,但其expr必须产生一个列表,而且unquote-splicing表必须出现在一个产生一个列表或向量的上下文里。顾名思义,生成的列表被拼接到它自己使用的上下文中。
例如:
> (quasiquote (1 2 (unquote-splicing (list (+ 1 2) (- 5 1))) 5))
'(1 2 3 4 5)
使用拼接,我们可以修改上面的示例表达式的构造,只需要一个let表达式和一个单个+表达式。
例如:
> (define (build-exp n)
(add-lets
n
(quasiquote (+ (unquote-splicing
(build-list
n
(λ (x) (n->var (+ x 1)))))))))
> (define (add-lets n body)
(quasiquote
(let (unquote
(build-list
n
(λ (n)
(quasiquote
[(unquote (n->var (+ n 1))) (unquote (+ n 1))]))))
(unquote body))))
> (define (n->var n) (string->symbol (format "x~a" n)))
> (build-exp 3)
'(let ((x1 1) (x2 2) (x3 3)) (+ x1 x2 x3))
如果一个quasiquote表出现在一个封闭的quasiquote表里,那这个内部的quasiquote有效地删除unquote和unquote-splicing表的一层,结果第二层unquote和unquote-splicing表是必要的。
例如:
> (quasiquote (1 2 (quasiquote (unquote (+ 1 2)))))
'(1 2 (quasiquote (unquote (+ 1 2))))
> (quasiquote (1 2 (quasiquote (unquote (unquote (+ 1 2))))))
'(1 2 (quasiquote (unquote 3)))
> (quasiquote (1 2 (quasiquote ((unquote (+ 1 2)) (unquote (unquote (- 5 1)))))))
'(1 2 (quasiquote ((unquote (+ 1 2)) (unquote 4))))
上面的求值实际上不会像显示那样打印。相反,quasiquote和unquote的简写形式将被使用:`(即一个反引号)和,(即一个逗号)。同样的简写可在表达式中使用:
例如:
> `(1 2 `(,(+ 1 2) ,,(- 5 1)))
'(1 2 `(,(+ 1 2) ,4))
unquote-splicing简写形式是,@:
例如:
> `(1 2 ,@(list (+ 1 2) (- 5 1)))
'(1 2 3 4)