|
56 | 56 | (check (case* 'yes |
57 | 57 | ((yes no) 'boolean) |
58 | 58 | (else 'unknown)) |
59 | | - => 'boolean) |
| 59 | + => 'boolean |
| 60 | +) ;check |
60 | 61 |
|
61 | 62 | (check (case* 'no |
62 | 63 | ((yes no) 'boolean) |
63 | 64 | (else 'unknown)) |
64 | | - => 'boolean) |
| 65 | + => 'boolean |
| 66 | +) ;check |
65 | 67 |
|
66 | 68 | (check (case* 'maybe |
67 | 69 | ((yes no) 'boolean) |
68 | 70 | (else 'unknown)) |
69 | | - => 'unknown) |
| 71 | + => 'unknown |
| 72 | +) ;check |
70 | 73 |
|
71 | 74 | ;; 数字匹配 |
72 | 75 | (check (case* 42 |
73 | 76 | ((1 2 3) 'small) |
74 | 77 | ((42 100) 'big) |
75 | 78 | (else 'other)) |
76 | | - => 'big) |
| 79 | + => 'big |
| 80 | +) ;check |
77 | 81 |
|
78 | 82 | ;; 字符串匹配 |
79 | 83 | (check (case* "hello" |
80 | 84 | (("hi" "hello") 'greeting) |
81 | 85 | (else 'other)) |
82 | | - => 'greeting) |
| 86 | + => 'greeting |
| 87 | +) ;check |
83 | 88 |
|
84 | 89 | ;; 混合类型匹配 |
85 | 90 | (check (case* 3.14 |
86 | 91 | ((1 2 3) 'integer) |
87 | 92 | ((3.14 2.71) 'float) |
88 | 93 | (else 'other)) |
89 | | - => 'float) |
| 94 | + => 'float |
| 95 | +) ;check |
90 | 96 |
|
91 | 97 | ;; ========== 列表字面量模式匹配测试 ========== |
92 | 98 |
|
93 | 99 | ;; 注意:case* 的列表模式需要完全匹配字面量 |
94 | 100 | (check (case* '(1 2 3) |
95 | 101 | (((1 2 3)) 'matched) |
96 | 102 | (else 'not-matched)) |
97 | | - => 'matched) |
| 103 | + => 'matched |
| 104 | +) ;check |
98 | 105 |
|
99 | 106 | ;; 不匹配的情况 |
100 | 107 | (check (case* '(1 2 3) |
101 | 108 | (((1 2)) 'two) |
102 | 109 | (((1 2 3)) 'three) |
103 | 110 | (else 'other)) |
104 | | - => 'three) |
| 111 | + => 'three |
| 112 | +) ;check |
105 | 113 |
|
106 | 114 | ;; ========== 标签绑定测试 ========== |
107 | 115 |
|
108 | 116 | ;; 简单标签捕获 - 注意:结果中用 #<x> 而非 x 引用 |
109 | 117 | (check (case* '(1 2) |
110 | 118 | (((#<x:> #<y:>)) (+ #<x> #<y>)) |
111 | 119 | (else 0)) |
112 | | - => 3) |
| 120 | + => 3 |
| 121 | +) ;check |
113 | 122 |
|
114 | 123 | ;; 在结果中使用标签 - 标签引用语法 #<label> |
115 | 124 | ;; 注意:'#<label> 中的引号 ' 是 quote 的简写,表示返回符号本身 |
116 | 125 | ;; 这里 '#<second> 和 '#<first> 分别被替换为捕获的值 'world 和 'hello |
117 | 126 | (check (case* '(hello world) |
118 | 127 | (((#<first:> #<second:>)) (list '#<second> '#<first>)) |
119 | 128 | (else '())) |
120 | | - => '(world hello)) |
| 129 | + => '(world hello) |
| 130 | +) ;check |
121 | 131 |
|
122 | 132 | ;; 标签值比较 |
123 | 133 | (check (case* '(5 5) |
124 | 134 | (((#<x:> #<y:>)) (if (= #<x> #<y>) 'same 'different)) |
125 | 135 | (else 'unknown)) |
126 | | - => 'same) |
| 136 | + => 'same |
| 137 | +) ;check |
127 | 138 |
|
128 | 139 | ;; ========== 谓词匹配测试 ========== |
129 | 140 |
|
|
132 | 143 | ((#<integer?>) 'integer) |
133 | 144 | ((#<string?>) 'string) |
134 | 145 | (else 'other)) |
135 | | - => 'integer) |
| 146 | + => 'integer |
| 147 | +) ;check |
136 | 148 |
|
137 | 149 | (check (case* "hello" |
138 | 150 | ((#<integer?>) 'integer) |
139 | 151 | ((#<string?>) 'string) |
140 | 152 | (else 'other)) |
141 | | - => 'string) |
| 153 | + => 'string |
| 154 | +) ;check |
142 | 155 |
|
143 | 156 | ;; 带标签的谓词匹配 - 使用 #<label:predicate?> 语法,结果中用 #<label> |
144 | 157 | (check (case* 42 |
145 | 158 | ((#<x:integer?>) (* #<x> 2)) |
146 | 159 | (else 0)) |
147 | | - => 84) |
| 160 | + => 84 |
| 161 | +) ;check |
148 | 162 |
|
149 | 163 | ;; 自定义谓词函数 |
150 | 164 | (check (case* 10 |
151 | 165 | ((#<even?>) 'even) |
152 | 166 | ((#<odd?>) 'odd) |
153 | 167 | (else 'unknown)) |
154 | | - => 'even) |
| 168 | + => 'even |
| 169 | +) ;check |
155 | 170 |
|
156 | 171 | (check (case* 7 |
157 | 172 | ((#<even?>) 'even) |
158 | 173 | ((#<odd?>) 'odd) |
159 | 174 | (else 'unknown)) |
160 | | - => 'odd) |
| 175 | + => 'odd |
| 176 | +) ;check |
161 | 177 |
|
162 | 178 | ;; ========== 向量模式匹配测试 ========== |
163 | 179 |
|
164 | 180 | ;; 基本向量匹配 |
165 | 181 | (check (case* #(1 2 3) |
166 | 182 | ((#(1 2 3)) 'matched) |
167 | 183 | (else 'no)) |
168 | | - => 'matched) |
| 184 | + => 'matched |
| 185 | +) ;check |
169 | 186 |
|
170 | 187 | ;; 向量中的标签捕获 |
171 | 188 | (check (case* #(10 20 30) |
172 | 189 | ((#(#<x:> 20 #<y:>)) (list #<x> #<y>)) |
173 | 190 | (else '())) |
174 | | - => '(10 30)) |
| 191 | + => '(10 30) |
| 192 | +) ;check |
175 | 193 |
|
176 | 194 | ;; ========== else 子句测试 ========== |
177 | 195 |
|
|
180 | 198 | ((a b c) 'abc) |
181 | 199 | ((x y z) 'xyz) |
182 | 200 | (else 'default)) |
183 | | - => 'default) |
| 201 | + => 'default |
| 202 | +) ;check |
184 | 203 |
|
185 | 204 | ;; ========== 边界情况测试 ========== |
186 | 205 |
|
187 | 206 | ;; 空列表匹配 |
188 | 207 | (check (case* '() |
189 | 208 | ((()) 'empty) |
190 | 209 | (else 'not-empty)) |
191 | | - => 'empty) |
| 210 | + => 'empty |
| 211 | +) ;check |
192 | 212 |
|
193 | 213 | ;; 单元素列表 |
194 | 214 | (check (case* '(only) |
195 | 215 | ((#<x:>) '#<x>) |
196 | 216 | (else 'none)) |
197 | | - => '(only)) |
| 217 | + => '(only) |
| 218 | +) ;check |
198 | 219 |
|
199 | 220 | ;; 单元素向量 |
200 | 221 | (check (case* #(42) |
201 | 222 | ((#(42)) 'forty-two) |
202 | 223 | (else 'none)) |
203 | | - => 'forty-two) |
| 224 | + => 'forty-two |
| 225 | +) ;check |
204 | 226 |
|
205 | 227 | ;; ========== 实际应用示例测试 ========== |
206 | 228 |
|
|
226 | 248 | (((* 1 #<x:>)) '#<x>) ; (* 1 x) => x |
227 | 249 | (((* #<x:> 1)) '#<x>) ; (* x 1) => x |
228 | 250 | (((* 0 #<...>)) 0) ; (* 0 ...) => 0 |
229 | | - (else expr))) |
| 251 | + (else expr) |
| 252 | + ) ;case* |
| 253 | +) ;define |
230 | 254 |
|
231 | 255 | (check (simplify '(+ 0 x)) => 'x) |
232 | 256 | (check (simplify '(+ x 0)) => 'x) |
|
262 | 286 | (((#<op:symbol?> #<args:...>)) 'application) |
263 | 287 | ((#<x:integer?>) 'integer-literal) |
264 | 288 | ((#<x:symbol?>) 'variable) |
265 | | - (else 'unknown))) |
| 289 | + (else 'unknown) |
| 290 | + ) ;case* |
| 291 | +) ;define |
266 | 292 |
|
267 | 293 | (check (expr-type '(lambda (x) x)) => 'lambda) |
268 | 294 | (check (expr-type '(if a b c)) => 'conditional) |
|
297 | 323 | ((()) 'empty) |
298 | 324 | (((#<x:>)) (list 'single '#<x>)) |
299 | 325 | (((#<a:> #<b:> #<rest:...>)) (list 'multiple #<a> #<b> #<rest>)) |
300 | | - (else 'other))) |
| 326 | + (else 'other) |
| 327 | + ) ;case* |
| 328 | +) ;define |
301 | 329 |
|
302 | 330 | (check (list-info '()) => 'empty) |
303 | 331 | (check (list-info '(one)) => '(single one)) |
|
311 | 339 | (((- #<a:integer?> #<b:integer?>)) (- #<a> #<b>)) |
312 | 340 | (((#<op:> #<args:...>)) (list 'unhandled-op '#<op> #<args>)) |
313 | 341 | ((#<x:integer?>) #<x>) |
314 | | - (else 'invalid))) |
| 342 | + (else 'invalid) |
| 343 | + ) ;case* |
| 344 | +) ;define |
315 | 345 |
|
316 | 346 | (check (calc '(+ 3 4)) => 7) |
317 | 347 | (check (calc '(- 10 3)) => 7) |
|
322 | 352 | (define (validate-user data) |
323 | 353 | (case* data |
324 | 354 | (((user (name #<n:string?>) (age #<a:integer?>))) |
325 | | - (and (> #<a> 0) (< #<a> 150))) |
326 | | - (else #f))) |
| 355 | + (and (> #<a> 0) (< #<a> 150)) |
| 356 | + ) ; |
| 357 | + (else #f) |
| 358 | + ) ;case* |
| 359 | +) ;define |
327 | 360 |
|
328 | 361 | (check (validate-user '(user (name "Alice") (age 30))) => #t) |
329 | 362 | (check (validate-user '(user (name "Bob") (age 200))) => #f) |
|
336 | 369 | (define (binop-expr? expr) |
337 | 370 | (case* expr |
338 | 371 | (((#<op:symbol?> #<left:> #<right:>)) |
339 | | - (list 'binop '#<op> '#<left> '#<right>)) |
340 | | - (else #f))) |
| 372 | + (list 'binop '#<op> '#<left> '#<right>) |
| 373 | + ) ; |
| 374 | + (else #f) |
| 375 | + ) ;case* |
| 376 | +) ;define |
341 | 377 |
|
342 | 378 | (check (binop-expr? '(+ 1 2)) => '(binop + 1 2)) |
343 | 379 | (check (binop-expr? '(* x y)) => '(binop * x y)) |
|
348 | 384 | (define (if-expr? expr) |
349 | 385 | (case* expr |
350 | 386 | (((if #<cond:> #<then:> #<else:>)) |
351 | | - (list 'if-expr '#<cond> '#<then> '#<else>)) |
352 | | - (else #f))) |
| 387 | + (list 'if-expr '#<cond> '#<then> '#<else>) |
| 388 | + ) ; |
| 389 | + (else #f) |
| 390 | + ) ;case* |
| 391 | +) ;define |
353 | 392 |
|
354 | 393 | (check (if-expr? '(if (> x 0) x (- x))) |
355 | | - => '(if-expr (> x 0) x (- x))) |
| 394 | + => '(if-expr (> x 0) x (- x)) |
| 395 | +) ;check |
356 | 396 | (check (if-expr? '(if flag then)) => #f) ; 缺少 else 分支 |
357 | 397 |
|
358 | 398 | (check-report) |
0 commit comments