-
Notifications
You must be signed in to change notification settings - Fork 1
/
closured_value.mdtlbl
116 lines (105 loc) · 2.81 KB
/
closured_value.mdtlbl
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
106
107
108
109
110
111
112
113
114
115
116
#**
* 这是在0.15.0添加的语法, 是一种特殊的值.
* 其用途可以在常量追值时对捕获表中进行求值
* 然后在展开前将捕获表中捕获的值加载
*
* 有两种捕获方式: 以take捕获 以const捕获
* 使用`A:B`表示以take捕获B到A, 相当于`take B=A;`
* 使用`&A:B`表示以const捕获B到A, 就不会take而是进行常量追值, 相当于`const B=A;`
*
* 有省略语法糖, 可以使用`A`表示`A:A`, 使用`&B`表示`&B:B`
*
* 语法起始处使用圆括号接方括号, 方括号内是捕获表, 方括号结束后接着一个值
*
* 在0.16.10添加了对label的捕获, 终于不用怕内层label和外层的同名了
* 使用方法在捕获的参数那里添加一个竖线, 然后在右边编写捕获的label
* 比如`([A B | :x](goto :x;))`
*#
const A = (a: print "makeA";);
const B = (b: print "makeB";);
const Clos = ([A &B](
# 因为闭包内部原理是将捕获值绑定到`..`, 所以你可以在其中重新修改它
# 但是因为在求值前就已经将内部注册量加载完毕了, 所以无法从加载完毕的值获取
# 例如你可以用`...B`获取而不能使用`B`
take ...B = makedB;
print "run" A B ...B;
));
print "inited";
const A = "errA"; # 因为闭包值在常量追值时就将值记录, 所以不会拿到这个
const B = "errB"; # 因为闭包值在常量追值时就将值记录, 所以不会拿到这个
print "do";
take Clos Clos;
#* >>>
print "makeA"
print "inited"
print "do"
print "run"
print a
print "makeB"
print b
print makedB
print "run"
print a
print makedB
print makedB
*#
# 在没有闭包语法时, 要实现闭包会比较麻烦
# 比如以如下办法实现
take Clos = ();
take Clos.A = (a: print "makeA";);
const Clos.B = (b: print "makeB";);
const Clos.V = (
print "run" ...A ...B;
);
print "inited";
print "do";
take Clos.V;
# 使用闭包捕获标记, 不会被内层跳转影响
const F = (
const Run = (const match @ {
F {
:x
print "unexpected";
take F[];
}
});
:x
print "expected";
take Run[([| :x](
goto :x;
))];
);
take F F; # 这里证明它不会被展开标签重命名破坏
#* >>>
print "expected"
print "unexpected"
jump 0 always 0 0
print "expected"
print "unexpected"
jump 3 always 0 0
*#
# 可以看到, 并没有跳到Run里面的:x, 而是闭包捕获到的
# 如果我们将闭包去掉的话, 会得到我们不希望看到的, 如下
#* >>>
print "expected"
print "unexpected"
jump 1 always 0 0
print "expected"
print "unexpected"
jump 4 always 0 0
*#
# 在0.17.10版本添加了捕获环境参数的功能, 会在展开闭包前设置环境参数
const Builder = (
const X = 2;
const $.F = ([X @](
print X @;
));
);
const Clos = Builder[a b c]->F;
take Clos[d e f];
#* >>>
print 2
print a
print b
print c
*#