Convert almost everything to use new import syntax.
catseye
13 years ago
82 | 82 | |
83 | 83 | > loadModules mc Null = do |
84 | 84 | > return (mc, Env.empty) |
85 | > loadModules mc (Pair (Symbol name) (Pair version (Pair qualifiers rest))) = do | |
86 | > let (rest', qualified) = case qualifiers of | |
87 | > (Symbol _) -> ((Pair qualifiers rest), False) | |
88 | > _ -> (rest, True) | |
89 | > loadModuleBySpec mc name version qualified rest' | |
90 | > loadModules mc (Pair (Symbol name) (Pair version rest)) = do | |
91 | > loadModuleBySpec mc name version False rest | |
92 | ||
93 | > loadModuleBySpec mc name version qualified rest = do | |
85 | > loadModules mc (Pair (Pair (Symbol name) (Pair version qualifiers)) rest) = do | |
86 | > let qualified = case qualifiers of | |
87 | > (Pair (Symbol "*") Null) -> False | |
88 | > Null -> True | |
94 | 89 | > (major, minor) <- parseVersion version |
95 | 90 | > (mc', nextEnv) <- loadModules mc rest |
96 | 91 | > (mc'', thisEnv) <- loadModule mc' (name, major, minor) qualified |
97 | 92 | > return (mc'', Env.union nextEnv thisEnv) |
98 | 93 | |
99 | > parseVersion (Pair (Number major) (Number minor)) = do | |
94 | > parseVersion (Pair (Number major) (Pair (Number minor) Null)) = do | |
100 | 95 | > case (denominator major, denominator minor) of |
101 | 96 | > (1, 1) -> return (numerator major, numerator minor) |
102 | 97 | > _ -> error "version number components can't be fractions" |
21 | 21 | > legalSymbolic = (char '*' <|> char '-' <|> char '/' <|> |
22 | 22 | > char '+' <|> char '<' <|> char '>' <|> |
23 | 23 | > char '<' <|> char '=' <|> char '?' <|> |
24 | > char '_' <|> char '!' <|> char '$') | |
24 | > char '_' <|> char '!' <|> char '$' <|> | |
25 | > char ':') | |
25 | 26 | |
26 | 27 | > symbol = do |
27 | 28 | > c <- (letter <|> legalSymbolic) |
21 | 21 | The `VERSION` gives the version of the Robin semantics in use. It has |
22 | 22 | the syntax: |
23 | 23 | |
24 | (NAT . NAT) | |
24 | (NAT NAT) | |
25 | 25 | |
26 | 26 | ...where `NAT` is a natural number (an integer not less than zero.) |
27 | 27 | More on versions later; the only version of Robin that currently |
28 | exists is 0.1 (aka `(0 . 1)`), so we'll use that. | |
28 | exists is 0.1 (aka `(0 1)`), so we'll use that. | |
29 | 29 | |
30 | 30 | The list of `MODULE-SPEC`s may be empty. So, without further ado, |
31 | 31 | here is one of the simplest Robin programs one can write: |
32 | 32 | |
33 | | (robin (0 . 1) () #t) | |
33 | | (robin (0 1) () #t) | |
34 | 34 | = #t |
35 | 35 | |
36 | 36 | Versioning |
58 | 58 | An implementation might, obviously, provide or not provide any |
59 | 59 | particular version of the language. |
60 | 60 | |
61 | | (robin (0 . 781) () #t) | |
62 | ? robin: unsupported language version (0 . 781) | |
61 | | (robin (0 781) () #t) | |
62 | ? unsupported language version (0 781) | |
63 | 63 | |
64 | 64 | The Robin semantics brought in by the version number in the `robin` |
65 | 65 | form include things like datatypes and evaluation rules, and are not |
101 | 101 | Here is an example of importing a module (but not doing anything |
102 | 102 | with it.) |
103 | 103 | |
104 | | (robin (0 . 1) (core (0 . 1)) #t) | |
104 | | (robin (0 1) ((core (0 1))) #t) | |
105 | 105 | = #t |
106 | 106 | |
107 | 107 | A particular version of a module might, naturally, not be available. |
109 | 109 | (TODO: The particular error message produced here may differ. Falderal |
110 | 110 | needs a forigiving-error-message option.) |
111 | 111 | |
112 | | (robin (0 . 1) (small (0 . 781)) #t) | |
113 | ? robin: module/small_0_781.robin: openFile: does not exist (No such file or directory) | |
112 | | (robin (0 1) ((small (0 781))) #t) | |
113 | ? module/small_0_781.robin: openFile: does not exist (No such file or directory) | |
114 | 114 | |
115 | 115 | And a particular module might, naturally, not even be available. |
116 | 116 | |
117 | | (robin (0 . 1) (gzgptzgztxxky (1 . 0)) #t) | |
118 | ? robin: module/gzgptzgztxxky_1_0.robin: openFile: does not exist (No such file or directory) | |
117 | | (robin (0 1) ((gzgptzgztxxky (1 0))) #t) | |
118 | ? module/gzgptzgztxxky_1_0.robin: openFile: does not exist (No such file or directory) | |
119 | 119 | |
120 | 120 | And a particular version of a module may rely on a particular version |
121 | 121 | of the fundamental semantics, so some combinations may not make sense. |
122 | 122 | For example, if `small` 3.0 relies on Robin 2.0, this will fail |
123 | 123 | (with a more appropriate error message like "Robin 2.0 required"): |
124 | 124 | |
125 | | (robin (1 . 0) (small (3 . 0)) #t) | |
126 | ? robin: unsupported language version (1 . 0) | |
125 | | (robin (1 0) ((small (3 0))) #t) | |
126 | ? unsupported language version (1 . 0) | |
127 | ||
128 | By default, identifiers are imported qualified. | |
129 | ||
130 | | (robin (0 1) ((core (0 1))) | |
131 | | (core:number? 3/5)) | |
132 | = #t | |
133 | ||
134 | | (robin (0 1) ((core (0 1))) | |
135 | | (number? 3/5)) | |
136 | ? undefined identifier number? | |
137 | ||
138 | The `*` qualifier imports a module unqualified. | |
139 | ||
140 | | (robin (0 1) ((core (0 1) *)) | |
141 | | (number? 3/5)) | |
142 | = #t | |
143 | ||
144 | | (robin (0 1) ((core (0 1) *)) | |
145 | | (core:number? 3/5)) | |
146 | ? undefined identifier core:number? | |
127 | 147 | |
128 | 148 | Intrinsic Data Types |
129 | 149 | -------------------- |
165 | 185 | module for this purpose, as it is the most straightforward way to create |
166 | 186 | a literal symbol in a Robin program. |
167 | 187 | |
168 | | (robin (0 . 1) (small (0 . 1)) | |
169 | | (literal hello)) | |
188 | | (robin (0 1) ((small (0 1) *)) | |
189 | | (small:literal hello)) | |
170 | 190 | = hello |
171 | 191 | |
172 | 192 | A Robin program is not expected to be able to generate new symbols |
201 | 221 | |
202 | 222 | For example, 5 is a rational number: |
203 | 223 | |
204 | | (robin (0 . 1) () 5) | |
224 | | (robin (0 1) () 5) | |
205 | 225 | = 5 |
206 | 226 | |
207 | 227 | The literal syntax for rational numbers allows one to use `/` to |
208 | 228 | denote a fraction: |
209 | 229 | |
210 | | (robin (0 . 1) () 4/5) | |
230 | | (robin (0 1) () 4/5) | |
211 | 231 | = 4/5 |
212 | 232 | |
213 | 233 | Rational numbers always evaluate to themselves. |
250 | 270 | Macros are represented as the S-expression expansion of their |
251 | 271 | implementation, except in the case of built-in macros. |
252 | 272 | |
253 | | (robin (0 . 1) (core (0 . 1)) | |
254 | | (macro (self args env) args)) | |
273 | | (robin (0 1) ((core (0 1))) | |
274 | | (core:macro (self args env) args)) | |
255 | 275 | = (macro (self args env) args) |
256 | 276 | |
257 | 277 | A built-in macro is represented thusly. (TODO: this representation |
258 | 278 | has problems; see section on pairs below.) |
259 | 279 | |
260 | | (robin (0 . 1) (core (0 . 1)) | |
261 | | pair) | |
280 | | (robin (0 1) ((core (0 1))) | |
281 | | core:pair) | |
262 | 282 | = (builtin pair) |
263 | 283 | |
264 | 284 | One upshot of built-in macros is that *all* intrinsic Robin functionality, |
265 | 285 | even things that in Scheme are special forms, can be passed around as |
266 | 286 | values. |
267 | 287 | |
268 | | (robin (0 . 1) (core (0 . 1)) | |
288 | | (robin (0 1) ((core (0 1) *)) | |
269 | 289 | | (pair if head)) |
270 | 290 | = ((builtin if) . (builtin head)) |
271 | 291 | |
279 | 299 | |
280 | 300 | TODO: write more about this. |
281 | 301 | |
282 | | (robin (0 . 1) (small (0 . 1)) | |
283 | | (literal (7 . 8))) | |
302 | | (robin (0 1) ((small (0 1))) | |
303 | | (small:literal (7 . 8))) | |
284 | 304 | = (7 . 8) |
285 | 305 | |
286 | 306 | Representations of some types (like built-in macros) look funny because they |
287 | 307 | don't follow the rules for depicting pairs with a dot and lists without -- |
288 | 308 | effectively, the parens are "fake" on these things. |
289 | 309 | |
290 | | (robin (0 . 1) (core (0 . 1)) | |
310 | | (robin (0 1) ((core (0 1) *)) | |
291 | 311 | | (pair #f boolean?)) |
292 | 312 | = (#f . (builtin boolean?)) |
293 | 313 | |
313 | 333 | Unlike Scheme, you do not need to quote `()`; it evaluates to itself |
314 | 334 | rather than indicating an illegal empty application. |
315 | 335 | |
316 | | (robin (0 . 1) () ()) | |
336 | | (robin (0 1) () ()) | |
317 | 337 | = () |
318 | 338 | |
319 | 339 | ### Alists ### |
339 | 359 | specifying literal strings. The characters of the string are given |
340 | 360 | between pairs of single quotes. |
341 | 361 | |
342 | | (robin (0 . 1) (small (0 . 1)) | |
362 | | (robin (0 1) ((small (0 1) *)) | |
343 | 363 | | (literal ''Hello'')) |
344 | 364 | = (72 101 108 108 111) |
345 | 365 | |
346 | 366 | A single single quote may appear in string literals of this kind. |
347 | 367 | |
348 | | (robin (0 . 1) (small (0 . 1)) | |
368 | | (robin (0 1) ((small (0 1) *)) | |
349 | 369 | | (literal ''He'llo'')) |
350 | 370 | = (72 101 39 108 108 111) |
351 | 371 | |
354 | 374 | match the sentinel given between the trailing single quote pair. The |
355 | 375 | sentinel may consist of any text not containing a single quote. |
356 | 376 | |
357 | | (robin (0 . 1) (small (0 . 1)) | |
377 | | (robin (0 1) ((small (0 1) *)) | |
358 | 378 | | (literal 'X'Hello'X')) |
359 | 379 | = (72 101 108 108 111) |
360 | 380 | |
361 | | (robin (0 . 1) (small (0 . 1)) | |
381 | | (robin (0 1) ((small (0 1) *)) | |
362 | 382 | | (literal '...@('Hello'...@(')) |
363 | 383 | = (72 101 108 108 111) |
364 | 384 | |
365 | | (robin (0 . 1) (small (0 . 1)) | |
385 | | (robin (0 1) ((small (0 1) *)) | |
366 | 386 | | (literal 'X'Hello'Y')) |
367 | 387 | ? (line 3, column 1): |
368 | 388 | ? unexpected end of input |
370 | 390 | |
371 | 391 | A sentinelized literal like this may embed a pair of single quotes. |
372 | 392 | |
373 | | (robin (0 . 1) (small (0 . 1)) | |
393 | | (robin (0 1) ((small (0 1) *)) | |
374 | 394 | | (literal 'X'Hel''lo'X')) |
375 | 395 | = (72 101 108 39 39 108 111) |
376 | 396 | |
377 | 397 | By choosing different sentinels, string literals may contain any other |
378 | 398 | string literal. |
379 | 399 | |
380 | | (robin (0 . 1) (small (0 . 1)) | |
400 | | (robin (0 1) ((small (0 1) *)) | |
381 | 401 | | (literal 'X'Hel'Y'bye'Y'lo'X')) |
382 | 402 | = (72 101 108 39 89 39 98 121 101 39 89 39 108 111) |
383 | 403 | |
385 | 405 | (Functions to convert escape sequences commonly found in other languages |
386 | 406 | may one day be available in a standard module.) |
387 | 407 | |
388 | | (robin (0 . 1) (small (0 . 1)) | |
408 | | (robin (0 1) ((small (0 1) *)) | |
389 | 409 | | (literal ''Hello\nworld'')) |
390 | 410 | = (72 101 108 108 111 92 110 119 111 114 108 100) |
391 | 411 | |
392 | 412 | All characters which appear in the source text between the delimiters |
393 | 413 | of the string literal are literally included in the string. |
394 | 414 | |
395 | | (robin (0 . 1) (small (0 . 1)) | |
415 | | (robin (0 1) ((small (0 1) *)) | |
396 | 416 | | (literal ''Hello |
397 | 417 | | world'')) |
398 | 418 | = (72 101 108 108 111 10 119 111 114 108 100) |
399 | 419 | |
400 | 420 | Adjacent string literals are not automatically concatenated. |
401 | 421 | |
402 | | (robin (0 . 1) (small (0 . 1)) | |
422 | | (robin (0 1) ((small (0 1) *)) | |
403 | 423 | | (literal (''Hello'' ''world''))) |
404 | 424 | = ((72 101 108 108 111) (119 111 114 108 100)) |
405 | 425 | |
406 | 426 | A string literal may appear in the tail of an improper list. |
407 | 427 | |
408 | | (robin (0 . 1) (small (0 . 1)) | |
428 | | (robin (0 1) ((small (0 1) *)) | |
409 | 429 | | (literal (a b c . ''123''))) |
410 | 430 | = (a b c 49 50 51) |
411 | 431 | |
415 | 435 | Any S-expression preceded by a `;` symbol is a comment. It will still |
416 | 436 | be parsed, but it will be ignored. |
417 | 437 | |
418 | | (robin (0 . 1) (core (0 . 1)) | |
438 | | (robin (0 1) ((core (0 1) *)) | |
419 | 439 | | ;(this program produces a pair of booleans) |
420 | 440 | | (pair #f #f)) |
421 | 441 | = (#f . #f) |
423 | 443 | Because S-expressions may nest, and because comments may appear |
424 | 444 | inside S-expressions, comments may nest. |
425 | 445 | |
426 | | (robin (0 . 1) (core (0 . 1)) | |
446 | | (robin (0 1) ((core (0 1) *)) | |
427 | 447 | | ;(this program produces |
428 | 448 | | ;(what you might call) |
429 | 449 | | a pair of booleans) |
432 | 452 | |
433 | 453 | Comments are still parsed. A syntax error in a comment is an error. |
434 | 454 | |
435 | | (robin (0 . 1) (core (0 . 1)) | |
455 | | (robin (0 1) ((core (0 1) *)) | |
436 | 456 | | ;(this program produces |
437 | 457 | | #k |
438 | 458 | | a pair of booleans) |
443 | 463 | |
444 | 464 | Any number of comments may appear together. |
445 | 465 | |
446 | | (robin (0 . 1) (core (0 . 1)) | |
466 | | (robin (0 1) ((core (0 1) *)) | |
447 | 467 | | (pair ;what ;on ;earth #f #f)) |
448 | 468 | = (#f . #f) |
449 | 469 | |
450 | 470 | Comments may appear before a closing parenthesis. |
451 | 471 | |
452 | | (robin (0 . 1) (core (0 . 1)) | |
472 | | (robin (0 1) ((core (0 1) *)) | |
453 | 473 | | (pair #f #f ;foo)) |
454 | 474 | = (#f . #f) |
455 | 475 | |
456 | | (robin (0 . 1) (core (0 . 1)) | |
476 | | (robin (0 1) ((core (0 1) *)) | |
457 | 477 | | (pair #f #f ;peace ;(on) ;earth)) |
458 | 478 | = (#f . #f) |
459 | 479 | |
460 | 480 | Comments may appear in the tail of an improper list. |
461 | 481 | |
462 | | (robin (0 . 1) (small (0 . 1)) | |
482 | | (robin (0 1) ((core (0 1) *)) | |
463 | 483 | | (literal (a . ;foo b))) |
464 | 484 | = (a . b) |
465 | 485 | |
466 | | (robin (0 . 1) (small (0 . 1)) | |
486 | | (robin (0 1) ((core (0 1) *)) | |
467 | 487 | | (literal (a . ;warp ;factor ;7 b))) |
468 | 488 | = (a . b) |
469 | 489 | |
470 | | (robin (0 . 1) (small (0 . 1)) | |
490 | | (robin (0 1) ((core (0 1) *)) | |
471 | 491 | | (literal (a . b ;foo))) |
472 | 492 | = (a . b) |
473 | 493 | |
474 | | (robin (0 . 1) (small (0 . 1)) | |
494 | | (robin (0 1) ((core (0 1) *)) | |
475 | 495 | | (literal (a . b ;warp ;factor ;7))) |
476 | 496 | = (a . b) |
477 | 497 | |
478 | 498 | Comments may appear in an empty list. |
479 | 499 | |
480 | | (robin (0 . 1) () | |
500 | | (robin (0 1) () | |
481 | 501 | | ( ;hi ;there)) |
482 | 502 | = () |
483 | 503 | |
484 | 504 | Comments need not be preceded by spaces. |
485 | 505 | |
486 | | (robin (0 . 1) () | |
506 | | (robin (0 1) () | |
487 | 507 | | (;north;by;north;west)) |
488 | 508 | = () |
489 | 509 | |
490 | 510 | To put truly arbitrary text in a comment, the string sugar syntax may be |
491 | 511 | used. |
492 | 512 | |
493 | | (robin (0 . 1) (core (0 . 1)) | |
513 | | (robin (0 1) ((core (0 1) *)) | |
494 | 514 | | ;''This program, it produces a pair of booleans. #k ?'' |
495 | 515 | | (pair #f #f)) |
496 | 516 | = (#f . #f) |
117 | 117 | test program which simply imports all of those modules; if any of them |
118 | 118 | fail static analysis, an exception will be thrown at import time: |
119 | 119 | |
120 | (robin (0 . 1) (foo (0 . 1) bar (0 . 1) baz (0 . 1)) | |
120 | (robin (0 1) ((foo (0 1) *) (bar (0 1) *) (baz (0 1) *)) | |
121 | 121 | #t) |
122 | 122 | |
123 | 123 | There is also room here for optimization. If static analysis for a module |
9 | 9 | |
10 | 10 | ### `+` ### |
11 | 11 | |
12 | | (robin (0 . 1) (arith (0 . 1)) | |
12 | | (robin (0 1) ((arith (0 1) *)) | |
13 | 13 | | (+ 14 23)) |
14 | 14 | = 37 |
15 | 15 | |
16 | 16 | ### `-` ### |
17 | 17 | |
18 | | (robin (0 . 1) (arith (0 . 1)) | |
18 | | (robin (0 1) ((arith (0 1) *)) | |
19 | 19 | | (- 23 10)) |
20 | 20 | = 13 |
21 | 21 | |
22 | 22 | ### `*` ### |
23 | 23 | |
24 | | (robin (0 . 1) (arith (0 . 1)) | |
24 | | (robin (0 1) ((arith (0 1) *)) | |
25 | 25 | | (* 23 10)) |
26 | 26 | = 230 |
27 | 27 | |
28 | 28 | ### `/` ### |
29 | 29 | |
30 | | (robin (0 . 1) (arith (0 . 1)) | |
30 | | (robin (0 1) ((arith (0 1) *)) | |
31 | 31 | | (/ 33 11)) |
32 | 32 | = 3 |
33 | 33 | |
34 | 34 | ### `abs` ### |
35 | 35 | |
36 | | (robin (0 . 1) (arith (0 . 1)) | |
36 | | (robin (0 1) ((arith (0 1) *)) | |
37 | 37 | | (abs 5)) |
38 | 38 | = 5 |
39 | 39 | |
40 | | (robin (0 . 1) (arith (0 . 1)) | |
40 | | (robin (0 1) ((arith (0 1) *)) | |
41 | 41 | | (abs (- 0 5))) |
42 | 42 | = 5 |
43 | 43 | |
44 | | (robin (0 . 1) (arith (0 . 1)) | |
44 | | (robin (0 1) ((arith (0 1) *)) | |
45 | 45 | | (abs 0)) |
46 | 46 | = 0 |
47 | 47 | |
48 | 48 | ### `frac` ### |
49 | 49 | |
50 | | (robin (0 . 1) (arith (0 . 1)) | |
50 | | (robin (0 1) ((arith (0 1) *)) | |
51 | 51 | | (frac 6/5)) |
52 | 52 | = 1/5 |
53 | 53 | |
54 | | (robin (0 . 1) (arith (0 . 1)) | |
54 | | (robin (0 1) ((arith (0 1) *)) | |
55 | 55 | | (frac (- 0 6/5))) |
56 | 56 | = 1/5 |
57 | 57 | |
58 | | (robin (0 . 1) (arith (0 . 1)) | |
58 | | (robin (0 1) ((arith (0 1) *)) | |
59 | 59 | | (frac 8)) |
60 | 60 | = 0 |
61 | 61 | |
62 | 62 | ### `integer?` ### |
63 | 63 | |
64 | | (robin (0 . 1) (arith (0 . 1)) | |
64 | | (robin (0 1) ((arith (0 1) *)) | |
65 | 65 | | (integer? 6/5)) |
66 | 66 | = #f |
67 | 67 | |
68 | | (robin (0 . 1) (arith (0 . 1)) | |
68 | | (robin (0 1) ((arith (0 1) *)) | |
69 | 69 | | (integer? 8)) |
70 | 70 | = #t |
71 | 71 | |
72 | | (robin (0 . 1) (arith (0 . 1)) | |
72 | | (robin (0 1) ((arith (0 1) *)) | |
73 | 73 | | (integer? 0)) |
74 | 74 | = #t |
75 | 75 | |
76 | | (robin (0 . 1) (arith (0 . 1)) | |
76 | | (robin (0 1) ((arith (0 1) *)) | |
77 | 77 | | (integer? (- 0 8))) |
78 | 78 | = #t |
79 | 79 | |
80 | 80 | ### `div` ### |
81 | 81 | |
82 | | (robin (0 . 1) (arith (0 . 1)) | |
82 | | (robin (0 1) ((arith (0 1) *)) | |
83 | 83 | | (div 100 3)) |
84 | 84 | = 33 |
85 | 85 | |
86 | | (robin (0 . 1) (arith (0 . 1)) | |
86 | | (robin (0 1) ((arith (0 1) *)) | |
87 | 87 | | (div (- 0 100) 3)) |
88 | 88 | = -34 |
89 | 89 | |
90 | | (robin (0 . 1) (arith (0 . 1)) | |
90 | | (robin (0 1) ((arith (0 1) *)) | |
91 | 91 | | (div 100 (- 0 3))) |
92 | 92 | = -34 |
93 | 93 | |
94 | | (robin (0 . 1) (arith (0 . 1)) | |
94 | | (robin (0 1) ((arith (0 1) *)) | |
95 | 95 | | (div 1001/10 3)) |
96 | 96 | = 33 |
97 | 97 | |
98 | | (robin (0 . 1) (arith (0 . 1)) | |
98 | | (robin (0 1) ((arith (0 1) *)) | |
99 | 99 | | (div 100 10/3)) |
100 | 100 | = 33 |
101 | 101 | |
102 | | (robin (0 . 1) (arith (0 . 1)) | |
102 | | (robin (0 1) ((arith (0 1) *)) | |
103 | 103 | | (div 10 0)) |
104 | 104 | ? uncaught exception: (division-by-zero . 10) |
105 | 105 | |
106 | 106 | ### `rem` ### |
107 | 107 | |
108 | | (robin (0 . 1) (arith (0 . 1)) | |
108 | | (robin (0 1) ((arith (0 1) *)) | |
109 | 109 | | (rem 12 3)) |
110 | 110 | = 0 |
111 | 111 | |
112 | | (robin (0 . 1) (arith (0 . 1)) | |
112 | | (robin (0 1) ((arith (0 1) *)) | |
113 | 113 | | (rem 11 3)) |
114 | 114 | = 2 |
115 | 115 | |
116 | | (robin (0 . 1) (arith (0 . 1)) | |
116 | | (robin (0 1) ((arith (0 1) *)) | |
117 | 117 | | (rem 10 3)) |
118 | 118 | = 1 |
119 | 119 | |
120 | | (robin (0 . 1) (arith (0 . 1)) | |
120 | | (robin (0 1) ((arith (0 1) *)) | |
121 | 121 | | (rem 9 3)) |
122 | 122 | = 0 |
123 | 123 | |
124 | | (robin (0 . 1) (arith (0 . 1)) | |
124 | | (robin (0 1) ((arith (0 1) *)) | |
125 | 125 | | (rem (- 0 10) 3)) |
126 | 126 | = 2 |
127 | 127 | |
128 | | (robin (0 . 1) (arith (0 . 1)) | |
128 | | (robin (0 1) ((arith (0 1) *)) | |
129 | 129 | | (rem 10 (- 0 3))) |
130 | 130 | = -2 |
131 | 131 | |
132 | | (robin (0 . 1) (arith (0 . 1)) | |
132 | | (robin (0 1) ((arith (0 1) *)) | |
133 | 133 | | (rem 10 0)) |
134 | 134 | ? uncaught exception: (division-by-zero . 10) |
135 | 135 | |
136 | 136 | ### `>` ### |
137 | 137 | |
138 | | (robin (0 . 1) (arith (0 . 1)) | |
138 | | (robin (0 1) ((arith (0 1) *)) | |
139 | 139 | | (> 6 4)) |
140 | 140 | = #t |
141 | 141 | |
142 | | (robin (0 . 1) (arith (0 . 1)) | |
142 | | (robin (0 1) ((arith (0 1) *)) | |
143 | 143 | | (> 6 8)) |
144 | 144 | = #f |
145 | 145 | |
146 | | (robin (0 . 1) (arith (0 . 1)) | |
146 | | (robin (0 1) ((arith (0 1) *)) | |
147 | 147 | | (> 6 6)) |
148 | 148 | = #f |
149 | 149 | |
150 | 150 | ### `<` ### |
151 | 151 | |
152 | | (robin (0 . 1) (arith (0 . 1)) | |
152 | | (robin (0 1) ((arith (0 1) *)) | |
153 | 153 | | (< 6 4)) |
154 | 154 | = #f |
155 | 155 | |
156 | | (robin (0 . 1) (arith (0 . 1)) | |
156 | | (robin (0 1) ((arith (0 1) *)) | |
157 | 157 | | (< 6 8)) |
158 | 158 | = #t |
159 | 159 | |
160 | | (robin (0 . 1) (arith (0 . 1)) | |
160 | | (robin (0 1) ((arith (0 1) *)) | |
161 | 161 | | (< 6 6)) |
162 | 162 | = #f |
163 | 163 | |
164 | 164 | ### `>=` ### |
165 | 165 | |
166 | | (robin (0 . 1) (arith (0 . 1)) | |
166 | | (robin (0 1) ((arith (0 1) *)) | |
167 | 167 | | (>= 6 4)) |
168 | 168 | = #t |
169 | 169 | |
170 | | (robin (0 . 1) (arith (0 . 1)) | |
170 | | (robin (0 1) ((arith (0 1) *)) | |
171 | 171 | | (>= 6 8)) |
172 | 172 | = #f |
173 | 173 | |
174 | | (robin (0 . 1) (arith (0 . 1)) | |
174 | | (robin (0 1) ((arith (0 1) *)) | |
175 | 175 | | (>= 6 6)) |
176 | 176 | = #t |
177 | 177 | |
178 | 178 | ### `<=` ### |
179 | 179 | |
180 | | (robin (0 . 1) (arith (0 . 1)) | |
180 | | (robin (0 1) ((arith (0 1) *)) | |
181 | 181 | | (<= 6 4)) |
182 | 182 | = #f |
183 | 183 | |
184 | | (robin (0 . 1) (arith (0 . 1)) | |
184 | | (robin (0 1) ((arith (0 1) *)) | |
185 | 185 | | (<= 6 8)) |
186 | 186 | = #t |
187 | 187 | |
188 | | (robin (0 . 1) (arith (0 . 1)) | |
188 | | (robin (0 1) ((arith (0 1) *)) | |
189 | 189 | | (<= 6 6)) |
190 | 190 | = #t |
191 | 191 | |
192 | 192 | ### `natural?` ### |
193 | 193 | |
194 | | (robin (0 . 1) (arith (0 . 1)) | |
194 | | (robin (0 1) ((arith (0 1) *)) | |
195 | 195 | | (natural? 6/5)) |
196 | 196 | = #f |
197 | 197 | |
198 | | (robin (0 . 1) (arith (0 . 1)) | |
198 | | (robin (0 1) ((arith (0 1) *)) | |
199 | 199 | | (natural? 8)) |
200 | 200 | = #t |
201 | 201 | |
202 | | (robin (0 . 1) (arith (0 . 1)) | |
202 | | (robin (0 1) ((arith (0 1) *)) | |
203 | 203 | | (natural? 0)) |
204 | 204 | = #t |
205 | 205 | |
206 | | (robin (0 . 1) (arith (0 . 1)) | |
206 | | (robin (0 1) ((arith (0 1) *)) | |
207 | 207 | | (natural? (- 0 8))) |
208 | 208 | = #f |
9 | 9 | |
10 | 10 | ### `assert` ### |
11 | 11 | |
12 | | (robin (0 . 1) (small (0 . 1) assert (0 . 1)) | |
12 | | (robin (0 1) ((small (0 1) *) (assert (0 1) *)) | |
13 | 13 | | (assert (equal? 5 5) 7)) |
14 | 14 | = 7 |
15 | 15 | |
16 | | (robin (0 . 1) (small (0 . 1) assert (0 . 1)) | |
16 | | (robin (0 1) ((small (0 1) *) (assert (0 1) *)) | |
17 | 17 | | (assert (equal? 5 6) 7)) |
18 | 18 | ? uncaught exception: (assertion-failed equal? 5 6) |
19 | 19 | |
20 | 20 | ### `assert-boolean` ### |
21 | 21 | |
22 | | (robin (0 . 1) (small (0 . 1) assert (0 . 1)) | |
22 | | (robin (0 1) ((small (0 1) *) (assert (0 1) *)) | |
23 | 23 | | (assert-boolean #f 4)) |
24 | 24 | = 4 |
25 | 25 | |
26 | | (robin (0 . 1) (small (0 . 1) assert (0 . 1)) | |
26 | | (robin (0 1) ((small (0 1) *) (assert (0 1) *)) | |
27 | 27 | | (assert-boolean 4 #f)) |
28 | 28 | ? uncaught exception: (expected-boolean . 4) |
29 | 29 | |
30 | 30 | ### `assert-number` ### |
31 | 31 | |
32 | | (robin (0 . 1) (small (0 . 1) assert (0 . 1)) | |
32 | | (robin (0 1) ((small (0 1) *) (assert (0 1) *)) | |
33 | 33 | | (assert-number 4 #f)) |
34 | 34 | = #f |
35 | 35 | |
36 | | (robin (0 . 1) (small (0 . 1) assert (0 . 1)) | |
36 | | (robin (0 1) ((small (0 1) *) (assert (0 1) *)) | |
37 | 37 | | (assert-number #f 4)) |
38 | 38 | ? uncaught exception: (expected-number . #f) |
39 | 39 | |
40 | 40 | ### `assert-symbol` ### |
41 | 41 | |
42 | | (robin (0 . 1) (small (0 . 1) assert (0 . 1)) | |
42 | | (robin (0 1) ((small (0 1) *) (assert (0 1) *)) | |
43 | 43 | | (assert-symbol (literal captain) (literal tennille))) |
44 | 44 | = tennille |
45 | 45 | |
46 | | (robin (0 . 1) (small (0 . 1) assert (0 . 1)) | |
46 | | (robin (0 1) ((small (0 1) *) (assert (0 1) *)) | |
47 | 47 | | (assert-symbol 7 (literal what))) |
48 | 48 | ? uncaught exception: (expected-symbol . 7) |
49 | 49 | |
50 | 50 | ### `assert-pair` ### |
51 | 51 | |
52 | | (robin (0 . 1) (small (0 . 1) assert (0 . 1)) | |
52 | | (robin (0 1) ((small (0 1) *) (assert (0 1) *)) | |
53 | 53 | | (assert-pair (pair 1 2) #t)) |
54 | 54 | = #t |
55 | 55 | |
56 | | (robin (0 . 1) (small (0 . 1) assert (0 . 1)) | |
56 | | (robin (0 1) ((small (0 1) *) (assert (0 1) *)) | |
57 | 57 | | (assert-pair #t (pair 1 2))) |
58 | 58 | ? uncaught exception: (expected-pair . #t) |
59 | 59 | |
60 | 60 | ### `assert-macro` ### |
61 | 61 | |
62 | | (robin (0 . 1) (small (0 . 1) assert (0 . 1)) | |
62 | | (robin (0 1) ((small (0 1) *) (assert (0 1) *)) | |
63 | 63 | | (assert-macro literal (literal it-is))) |
64 | 64 | = it-is |
65 | 65 | |
66 | | (robin (0 . 1) (small (0 . 1) assert (0 . 1)) | |
66 | | (robin (0 1) ((small (0 1) *) (assert (0 1) *)) | |
67 | 67 | | (assert-macro (macro (self args env) args) (literal it-is))) |
68 | 68 | = it-is |
69 | 69 | |
70 | | (robin (0 . 1) (small (0 . 1) assert (0 . 1)) | |
70 | | (robin (0 1) ((small (0 1) *) (assert (0 1) *)) | |
71 | 71 | | (assert-macro 7 (literal what))) |
72 | 72 | ? uncaught exception: (expected-macro . 7) |
9 | 9 | |
10 | 10 | ### `and` ### |
11 | 11 | |
12 | | (robin (0 . 1) (boolean (0 . 1)) | |
12 | | (robin (0 1) ((boolean (0 1) *)) | |
13 | 13 | | (and #t #t)) |
14 | 14 | = #t |
15 | 15 | |
16 | | (robin (0 . 1) (boolean (0 . 1)) | |
16 | | (robin (0 1) ((boolean (0 1) *)) | |
17 | 17 | | (and #t #f)) |
18 | 18 | = #f |
19 | 19 | |
20 | | (robin (0 . 1) (boolean (0 . 1)) | |
20 | | (robin (0 1) ((boolean (0 1) *)) | |
21 | 21 | | (and #f #t)) |
22 | 22 | = #f |
23 | 23 | |
24 | | (robin (0 . 1) (boolean (0 . 1)) | |
24 | | (robin (0 1) ((boolean (0 1) *)) | |
25 | 25 | | (and #f #f)) |
26 | 26 | = #f |
27 | 27 | |
28 | 28 | `and` can take any number of arguments. |
29 | 29 | |
30 | | (robin (0 . 1) (boolean (0 . 1)) | |
30 | | (robin (0 1) ((boolean (0 1) *)) | |
31 | 31 | | (and)) |
32 | 32 | = #t |
33 | 33 | |
34 | | (robin (0 . 1) (boolean (0 . 1)) | |
34 | | (robin (0 1) ((boolean (0 1) *)) | |
35 | 35 | | (and #f)) |
36 | 36 | = #f |
37 | 37 | |
38 | | (robin (0 . 1) (boolean (0 . 1)) | |
38 | | (robin (0 1) ((boolean (0 1) *)) | |
39 | 39 | | (and #t #t #t #t #t)) |
40 | 40 | = #t |
41 | 41 | |
42 | | (robin (0 . 1) (boolean (0 . 1)) | |
42 | | (robin (0 1) ((boolean (0 1) *)) | |
43 | 43 | | (and #t #t #t #f)) |
44 | 44 | = #f |
45 | 45 | |
49 | 49 | |
50 | 50 | ### `or` ### |
51 | 51 | |
52 | | (robin (0 . 1) (boolean (0 . 1)) | |
52 | | (robin (0 1) ((boolean (0 1) *)) | |
53 | 53 | | (or #t #t)) |
54 | 54 | = #t |
55 | 55 | |
56 | | (robin (0 . 1) (boolean (0 . 1)) | |
56 | | (robin (0 1) ((boolean (0 1) *)) | |
57 | 57 | | (or #t #f)) |
58 | 58 | = #t |
59 | 59 | |
60 | | (robin (0 . 1) (boolean (0 . 1)) | |
60 | | (robin (0 1) ((boolean (0 1) *)) | |
61 | 61 | | (or #f #t)) |
62 | 62 | = #t |
63 | 63 | |
64 | | (robin (0 . 1) (boolean (0 . 1)) | |
64 | | (robin (0 1) ((boolean (0 1) *)) | |
65 | 65 | | (or #f #f)) |
66 | 66 | = #f |
67 | 67 | |
68 | 68 | `or` can take any number of arguments. |
69 | 69 | |
70 | | (robin (0 . 1) (boolean (0 . 1)) | |
70 | | (robin (0 1) ((boolean (0 1) *)) | |
71 | 71 | | (or)) |
72 | 72 | = #f |
73 | 73 | |
74 | | (robin (0 . 1) (boolean (0 . 1)) | |
74 | | (robin (0 1) ((boolean (0 1) *)) | |
75 | 75 | | (or #t)) |
76 | 76 | = #t |
77 | 77 | |
78 | | (robin (0 . 1) (boolean (0 . 1)) | |
78 | | (robin (0 1) ((boolean (0 1) *)) | |
79 | 79 | | (or #f #f #f #f #f)) |
80 | 80 | = #f |
81 | 81 | |
82 | | (robin (0 . 1) (boolean (0 . 1)) | |
82 | | (robin (0 1) ((boolean (0 1) *)) | |
83 | 83 | | (or #f #f #f #t)) |
84 | 84 | = #t |
85 | 85 | |
89 | 89 | |
90 | 90 | ### `not` ### |
91 | 91 | |
92 | | (robin (0 . 1) (boolean (0 . 1)) | |
92 | | (robin (0 1) ((boolean (0 1) *)) | |
93 | 93 | | (not #t)) |
94 | 94 | = #f |
95 | 95 | |
96 | | (robin (0 . 1) (boolean (0 . 1)) | |
96 | | (robin (0 1) ((boolean (0 1) *)) | |
97 | 97 | | (not #f)) |
98 | 98 | = #t |
99 | 99 | |
100 | | (robin (0 . 1) (boolean (0 . 1)) | |
100 | | (robin (0 1) ((boolean (0 1) *)) | |
101 | 101 | | (not #t #f)) |
102 | 102 | ? uncaught exception: (illegal-arguments #f) |
103 | 103 | |
104 | 104 | ### `xor` ### |
105 | 105 | |
106 | | (robin (0 . 1) (boolean (0 . 1)) | |
106 | | (robin (0 1) ((boolean (0 1) *)) | |
107 | 107 | | (xor #t #t)) |
108 | 108 | = #f |
109 | 109 | |
110 | | (robin (0 . 1) (boolean (0 . 1)) | |
110 | | (robin (0 1) ((boolean (0 1) *)) | |
111 | 111 | | (xor #t #f)) |
112 | 112 | = #t |
113 | 113 | |
114 | | (robin (0 . 1) (boolean (0 . 1)) | |
114 | | (robin (0 1) ((boolean (0 1) *)) | |
115 | 115 | | (xor #f #t)) |
116 | 116 | = #t |
117 | 117 | |
118 | | (robin (0 . 1) (boolean (0 . 1)) | |
118 | | (robin (0 1) ((boolean (0 1) *)) | |
119 | 119 | | (xor #f #f)) |
120 | 120 | = #f |
121 | 121 | |
122 | 122 | This test demonstrates that these functions really do evaluate their |
123 | 123 | arguments. |
124 | 124 | |
125 | | (robin (0 . 1) (boolean (0 . 1)) | |
125 | | (robin (0 1) ((boolean (0 1) *)) | |
126 | 126 | | (and (or (xor (and #t #t) #f) #f) #t)) |
127 | 127 | = #t |
39 | 39 | |
40 | 40 | `myself` expects exactly zero arguments. |
41 | 41 | |
42 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
42 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
43 | 43 | | (myself 123)) |
44 | 44 | ? uncaught exception: (illegal-arguments 123) |
45 | 45 | |
48 | 48 | `pid?` evaluates its argument, then evaluates to `#t` if that value |
49 | 49 | is a process identifier, `#f` otherwise. |
50 | 50 | |
51 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
51 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
52 | 52 | | (pid? (literal b))) |
53 | 53 | = #f |
54 | 54 | |
55 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
55 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
56 | 56 | | (pid? (myself))) |
57 | 57 | = #t |
58 | 58 | |
59 | 59 | The argument to `pid?` may naturally be of any type, but there |
60 | 60 | must be exactly one argument. |
61 | 61 | |
62 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
62 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
63 | 63 | | (pid?)) |
64 | 64 | ? uncaught exception: (illegal-arguments) |
65 | 65 | |
66 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
66 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
67 | 67 | | (pid? 200 500)) |
68 | 68 | ? uncaught exception: (illegal-arguments 200 500) |
69 | 69 | |
75 | 75 | proceeds to evaluate its third argument, in the current process, with |
76 | 76 | that new binding. |
77 | 77 | |
78 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
78 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
79 | 79 | | (spawn! worker (literal ok) |
80 | 80 | | (pid? worker))) |
81 | 81 | = #t |
82 | 82 | |
83 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
83 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
84 | 84 | | (spawn! worker (literal ok) |
85 | 85 | | (equal? (myself) worker))) |
86 | 86 | = #f |
87 | 87 | |
88 | 88 | `spawn!` takes exactly three arguments. |
89 | 89 | |
90 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
90 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
91 | 91 | | (spawn!)) |
92 | 92 | ? uncaught exception: (illegal-arguments) |
93 | 93 | |
94 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
94 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
95 | 95 | | (spawn! cheesecake)) |
96 | 96 | ? uncaught exception: (illegal-arguments cheesecake) |
97 | 97 | |
98 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
98 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
99 | 99 | | (spawn! (fun (x) 0) (fun (x) 1))) |
100 | 100 | ? uncaught exception: (illegal-arguments (fun (x) 0) (fun (x) 1)) |
101 | 101 | |
102 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
102 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
103 | 103 | | (spawn! (fun (x) 0) (fun (x) 1) |
104 | 104 | | (fun (x) 2) (fun (x) 3))) |
105 | 105 | ? uncaught exception: (illegal-arguments (fun (x) 0) (fun (x) 1) (fun (x) 2) (fun (x) 3)) |
106 | 106 | |
107 | 107 | The first argument to `spawn!` must be a symbol. |
108 | 108 | |
109 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
109 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
110 | 110 | | (spawn! #f (literal ok) 123)) |
111 | 111 | ? uncaught exception: (illegal-arguments #f (literal ok) 123) |
112 | 112 | |
117 | 117 | the process identified by the pid, then evaluates its third argument |
118 | 118 | and itself evaluates to that. |
119 | 119 | |
120 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
120 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
121 | 121 | | (spawn! worker (literal ok) |
122 | 122 | | (send! worker (literal spam) (literal ok)))) |
123 | 123 | = ok |
124 | 124 | |
125 | 125 | `send!` expects its first argument to be a pid. |
126 | 126 | |
127 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
127 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
128 | 128 | | (send! (literal eggs) (literal spam) (literal ok))) |
129 | 129 | ? uncaught exception: (expected-pid . eggs) |
130 | 130 | |
131 | 131 | `send!` expects exactly three arguments. |
132 | 132 | |
133 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
133 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
134 | 134 | | (spawn! worker (literal ok) |
135 | 135 | | (send! worker worker))) |
136 | 136 | ? uncaught exception: (illegal-arguments worker worker) |
137 | 137 | |
138 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
138 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
139 | 139 | | (spawn! worker (literal ok) |
140 | 140 | | (send! worker worker worker worker))) |
141 | 141 | ? uncaught exception: (illegal-arguments worker worker worker worker) |
147 | 147 | its first argument to the value so received, and evaluates its second |
148 | 148 | argument, and itself evaluates to that. |
149 | 149 | |
150 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
150 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
151 | 151 | | (bind parent (myself) |
152 | 152 | | (spawn! worker (send! parent (literal lettuce) (literal ok)) |
153 | 153 | | (recv! message (pair message message))))) |
157 | 157 | is a case of illegal arguments, as the identifier is not an expression |
158 | 158 | that must evaluate to a certain type.) |
159 | 159 | |
160 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
160 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
161 | 161 | | (bind parent (myself) |
162 | 162 | | (spawn! worker (send! parent (literal lettuce) (literal ok)) |
163 | 163 | | (recv! (pair 7 8) 9)))) |
165 | 165 | |
166 | 166 | `recv!` expects exactly two arguments. |
167 | 167 | |
168 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
168 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
169 | 169 | | (bind parent (myself) |
170 | 170 | | (spawn! worker (send! parent (literal lettuce) (literal ok)) |
171 | 171 | | (recv! message)))) |
172 | 172 | ? uncaught exception: (illegal-arguments message) |
173 | 173 | |
174 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
174 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
175 | 175 | | (bind parent (myself) |
176 | 176 | | (spawn! worker (send! parent (literal lettuce) (literal ok)) |
177 | 177 | | (recv! message message message)))) |
181 | 181 | |
182 | 182 | A process we spawned can send our message back to us. |
183 | 183 | |
184 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
184 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
185 | 185 | | (bind parent (myself) |
186 | 186 | | (spawn! worker (recv! message (send! parent message 123)) |
187 | 187 | | (send! worker (literal whoopie) |
190 | 190 | |
191 | 191 | A process we spawned can receive multiple messages. |
192 | 192 | |
193 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
193 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
194 | 194 | | (bind parent (myself) |
195 | 195 | | (spawn! worker |
196 | 196 | | (recv! message1 |
204 | 204 | A process we spawned will terminate while waiting for a message, if the |
205 | 205 | main process terminates. |
206 | 206 | |
207 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
207 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
208 | 208 | | (bind parent (myself) |
209 | 209 | | (spawn! worker |
210 | 210 | | (recv! message1 |
216 | 216 | |
217 | 217 | A spawned process can spawn processes of its own. |
218 | 218 | |
219 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
219 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
220 | 220 | | (bind parent (myself) |
221 | 221 | | (spawn! worker |
222 | 222 | | (bind subparent (myself) |
229 | 229 | A process can send messages to any process it knows about, not just |
230 | 230 | its parent. |
231 | 231 | |
232 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
232 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
233 | 233 | | (bind parent (myself) |
234 | 234 | | (spawn! worker |
235 | 235 | | (spawn! subworker |
241 | 241 | send!s a message to this effect to the process that spawn!ed it, |
242 | 242 | immediately before terminating. |
243 | 243 | |
244 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
244 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
245 | 245 | | (bind parent (myself) |
246 | 246 | | (spawn! worker |
247 | 247 | | (bind x (head ()) |
254 | 254 | `msgs?` evaluates to `#t` if the current process has one or more messages |
255 | 255 | waiting in its queue, `#f` otherwise. |
256 | 256 | |
257 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
257 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
258 | 258 | | (msgs?)) |
259 | 259 | = #f |
260 | 260 | |
261 | 261 | X Note: it's hard to write this test without a race condition... |
262 | 262 | X |
263 | X | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
263 | X | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
264 | 264 | X | (bind parent (myself) |
265 | 265 | X | (spawn! (send! parent (literal lettuce) (literal ok)) worker |
266 | 266 | X | (msgs?)))) |
268 | 268 | |
269 | 269 | `msgs?` expects exactly zero arguments. |
270 | 270 | |
271 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
271 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
272 | 272 | | (msgs? #t)) |
273 | 273 | ? uncaught exception: (illegal-arguments #t) |
274 | 274 | |
277 | 277 | `call!` combines `send!` and `recv!` to accomplish synchronous communication |
278 | 278 | with another process. |
279 | 279 | |
280 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
280 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
281 | 281 | | (spawn! worker |
282 | 282 | | (recv! message |
283 | 283 | | (let ((sender (head message)) |
294 | 294 | not finish. Note: this is an awful test, because an implementation |
295 | 295 | may in fact hang instead of doing what our implementation does. |
296 | 296 | |
297 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
297 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
298 | 298 | | (bind parent (myself) (spawn! worker |
299 | 299 | | (recv! message |
300 | 300 | | (let ((sender (head message)) |
307 | 307 | | (pair (literal reply-was) reply))))) |
308 | 308 | ? thread blocked indefinitely in an MVar operation |
309 | 309 | |
310 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
310 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
311 | 311 | | (bind parent (myself) (spawn! worker |
312 | 312 | | (recv! message |
313 | 313 | | (let ((send!er (head message)) |
325 | 325 | behavior or what (it's an exception message from any process, |
326 | 326 | currently!) but... we'll see. |
327 | 327 | |
328 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
328 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
329 | 329 | | (spawn! worker |
330 | 330 | | (recv! message |
331 | 331 | | (let ((send!er (head message)) |
338 | 338 | |
339 | 339 | `call!` expects its first argument to be a pid. |
340 | 340 | |
341 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
341 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
342 | 342 | | (call! (literal worker) this-tag (literal this-payload) reply |
343 | 343 | | (pair (literal reply-was) reply))) |
344 | 344 | ? uncaught exception: (expected-pid . worker) |
345 | 345 | |
346 | 346 | `call!` expects its second argument to be a symbol. |
347 | 347 | |
348 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
348 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
349 | 349 | | (call! (myself) #f (literal this-payload) reply |
350 | 350 | | (pair (literal reply-was) reply))) |
351 | 351 | ? uncaught exception: (illegal-arguments (myself) #f (literal this-payload) reply (pair (literal reply-was) reply)) |
352 | 352 | |
353 | 353 | `call!` expects its fourth argument to be an identifier. |
354 | 354 | |
355 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
355 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
356 | 356 | | (call! (myself) this-tag (literal this-payload) #f |
357 | 357 | | (pair (literal reply-was) reply))) |
358 | 358 | ? uncaught exception: (illegal-arguments (myself) this-tag (literal this-payload) #f (pair (literal reply-was) reply)) |
365 | 365 | the appropriate branch, sends a reply message to the pid that `call!`ed it, |
366 | 366 | and evaluates the tail of the branch. |
367 | 367 | |
368 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
368 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
369 | 369 | | (spawn! worker |
370 | 370 | | (respond! |
371 | 371 | | (donkey (x) (literal kong) (literal ok)) |
375 | 375 | |
376 | 376 | The payload of the `call!` is available in the bound variable. |
377 | 377 | |
378 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
378 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
379 | 379 | | (spawn! worker |
380 | 380 | | (respond! |
381 | 381 | | (donkey (x) (literal kong) (literal ok)) |
385 | 385 | |
386 | 386 | `respond!` respond!s to only one message. |
387 | 387 | |
388 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
388 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
389 | 389 | | (spawn! worker |
390 | 390 | | (respond! |
391 | 391 | | (donkey (x) (literal kong) (literal ok)) |
396 | 396 | |
397 | 397 | Typicall!y, to write a server, you would use it in a loop. |
398 | 398 | |
399 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
399 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
400 | 400 | | (bind work-fun (fun (self) |
401 | 401 | | (respond! |
402 | 402 | | (donkey (x) (literal kong) (self self)) |
411 | 411 | |
412 | 412 | `respond!` evaluates to the appropriate tail. |
413 | 413 | |
414 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1)) | |
414 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *)) | |
415 | 415 | | (bind parent (myself) (spawn! worker |
416 | 416 | | (call! parent take 71 reply (literal ok)) |
417 | 417 | | (respond! |
15 | 15 | `pair` evaluates both of its arguments, then evaluates to a pair which |
16 | 16 | contains both of those values, in the same order. |
17 | 17 | |
18 | | (robin (0 . 1) (core (0 . 1)) | |
18 | | (robin (0 1) ((core (0 1) *)) | |
19 | 19 | | (pair #t #f)) |
20 | 20 | = (#t . #f) |
21 | 21 | |
22 | | (robin (0 . 1) (core (0 . 1)) | |
22 | | (robin (0 1) ((core (0 1) *)) | |
23 | 23 | | (pair #t (pair #f ()))) |
24 | 24 | = (#t #f) |
25 | 25 | |
26 | 26 | Arguments to `pair` can be any type, but fewer than or more than |
27 | 27 | two arguments will raise an exception. |
28 | 28 | |
29 | | (robin (0 . 1) (core (0 . 1)) | |
29 | | (robin (0 1) ((core (0 1) *)) | |
30 | 30 | | (pair #t)) |
31 | 31 | ? uncaught exception: (illegal-arguments #t) |
32 | 32 | |
33 | | (robin (0 . 1) (core (0 . 1)) | |
33 | | (robin (0 1) ((core (0 1) *)) | |
34 | 34 | | (pair #f #t #f)) |
35 | 35 | ? uncaught exception: (illegal-arguments #f #t #f) |
36 | 36 | |
41 | 41 | `head` evaluates its argument to a pair, and evaluates to the first element |
42 | 42 | of that pair. |
43 | 43 | |
44 | | (robin (0 . 1) (core (0 . 1)) | |
44 | | (robin (0 1) ((core (0 1) *)) | |
45 | 45 | | (head (pair #t #f))) |
46 | 46 | = #t |
47 | 47 | |
48 | 48 | `head` expects its argument to be a pair. |
49 | 49 | |
50 | | (robin (0 . 1) (core (0 . 1)) | |
50 | | (robin (0 1) ((core (0 1) *)) | |
51 | 51 | | (head #f)) |
52 | 52 | ? uncaught exception: (expected-pair . #f) |
53 | 53 | |
54 | 54 | `head` expects exactly one argument. |
55 | 55 | |
56 | | (robin (0 . 1) (core (0 . 1)) | |
56 | | (robin (0 1) ((core (0 1) *)) | |
57 | 57 | | (head (pair #t #f) (pair #f #t))) |
58 | 58 | ? uncaught exception: (illegal-arguments (pair #t #f) (pair #f #t)) |
59 | 59 | |
60 | | (robin (0 . 1) (core (0 . 1)) | |
60 | | (robin (0 1) ((core (0 1) *)) | |
61 | 61 | | (head)) |
62 | 62 | ? uncaught exception: (illegal-arguments) |
63 | 63 | |
68 | 68 | `tail` evaluates its argument to a pair, and evaluates to the second element |
69 | 69 | of that pair. |
70 | 70 | |
71 | | (robin (0 . 1) (core (0 . 1)) | |
71 | | (robin (0 1) ((core (0 1) *)) | |
72 | 72 | | (tail (pair #t #f))) |
73 | 73 | = #f |
74 | 74 | |
75 | 75 | `tail` expects its argument to be a pair. |
76 | 76 | |
77 | | (robin (0 . 1) (core (0 . 1)) | |
77 | | (robin (0 1) ((core (0 1) *)) | |
78 | 78 | | (tail #f)) |
79 | 79 | ? uncaught exception: (expected-pair . #f) |
80 | 80 | |
81 | 81 | `tail` expects exactly one argument. |
82 | 82 | |
83 | | (robin (0 . 1) (core (0 . 1)) | |
83 | | (robin (0 1) ((core (0 1) *)) | |
84 | 84 | | (tail (pair #t #f) (pair #f #t))) |
85 | 85 | ? uncaught exception: (illegal-arguments (pair #t #f) (pair #f #t)) |
86 | 86 | |
87 | | (robin (0 . 1) (core (0 . 1)) | |
87 | | (robin (0 1) ((core (0 1) *)) | |
88 | 88 | | (tail)) |
89 | 89 | ? uncaught exception: (illegal-arguments) |
90 | 90 | |
97 | 97 | is `#f` it evaluates, and evaluates to, its third argument. In all cases, |
98 | 98 | at most two arguments are evaluated. |
99 | 99 | |
100 | | (robin (0 . 1) (core (0 . 1)) | |
100 | | (robin (0 1) ((core (0 1) *)) | |
101 | 101 | | (if #t 7 9)) |
102 | 102 | = 7 |
103 | 103 | |
104 | | (robin (0 . 1) (core (0 . 1)) | |
104 | | (robin (0 1) ((core (0 1) *)) | |
105 | 105 | | (if #f 7 9)) |
106 | 106 | = 9 |
107 | 107 | |
108 | 108 | The second and third arguments can be arbitrary expressions, but `if` |
109 | 109 | expects its first argument to be a boolean. |
110 | 110 | |
111 | | (robin (0 . 1) (core (0 . 1)) | |
111 | | (robin (0 1) ((core (0 1) *)) | |
112 | 112 | | (if 5 7 9)) |
113 | 113 | ? uncaught exception: (expected-boolean . 5) |
114 | 114 | |
115 | 115 | `if` expects exactly three arguments. |
116 | 116 | |
117 | | (robin (0 . 1) (core (0 . 1)) | |
117 | | (robin (0 1) ((core (0 1) *)) | |
118 | 118 | | (if #t 7)) |
119 | 119 | ? uncaught exception: (illegal-arguments #t 7) |
120 | 120 | |
121 | | (robin (0 . 1) (core (0 . 1)) | |
121 | | (robin (0 1) ((core (0 1) *)) | |
122 | 122 | | (if #t 7 8 9)) |
123 | 123 | ? uncaught exception: (illegal-arguments #t 7 8 9) |
124 | 124 | |
125 | 125 | The identifiers named in the branch which is not evaluated need not be |
126 | 126 | properly bound to values in the environment. |
127 | 127 | |
128 | | (robin (0 . 1) (core (0 . 1)) | |
128 | | (robin (0 1) ((core (0 1) *)) | |
129 | 129 | | (if #t 1 (pair fred ethel))) |
130 | 130 | = 1 |
131 | 131 | |
136 | 136 | |
137 | 137 | `equal?` works on symbols. |
138 | 138 | |
139 | | (robin (0 . 1) (core (0 . 1)) | |
139 | | (robin (0 1) ((core (0 1) *)) | |
140 | 140 | | (equal? |
141 | 141 | | ((macro (s a e) (head a)) this-symbol) |
142 | 142 | | ((macro (s a e) (head a)) this-symbol))) |
143 | 143 | = #t |
144 | 144 | |
145 | | (robin (0 . 1) (core (0 . 1)) | |
145 | | (robin (0 1) ((core (0 1) *)) | |
146 | 146 | | (equal? |
147 | 147 | | ((macro (s a e) (head a)) this-symbol) |
148 | 148 | | ((macro (s a e) (head a)) that-symbol))) |
150 | 150 | |
151 | 151 | `equal?` works on lists. |
152 | 152 | |
153 | | (robin (0 . 1) (core (0 . 1)) | |
153 | | (robin (0 1) ((core (0 1) *)) | |
154 | 154 | | (equal? (pair 1 (pair 2 (pair 3 ()))) |
155 | 155 | | (pair 1 (pair 2 (pair 3 ()))))) |
156 | 156 | = #t |
157 | 157 | |
158 | 158 | Two values of different types are never equal. |
159 | 159 | |
160 | | (robin (0 . 1) (core (0 . 1)) | |
160 | | (robin (0 1) ((core (0 1) *)) | |
161 | 161 | | (equal? #t |
162 | 162 | | (pair ((macro (self args env) (head args)) a) ()))) |
163 | 163 | = #f |
164 | 164 | |
165 | | (robin (0 . 1) (core (0 . 1)) | |
165 | | (robin (0 1) ((core (0 1) *)) | |
166 | 166 | | (equal? #f |
167 | 167 | | ())) |
168 | 168 | = #f |
170 | 170 | Arguments to `equal?` can be any type, but fewer than or more than |
171 | 171 | two arguments will raise an exception. |
172 | 172 | |
173 | | (robin (0 . 1) (core (0 . 1)) | |
173 | | (robin (0 1) ((core (0 1) *)) | |
174 | 174 | | (equal? 7)) |
175 | 175 | ? uncaught exception: (illegal-arguments 7) |
176 | 176 | |
177 | | (robin (0 . 1) (core (0 . 1)) | |
177 | | (robin (0 1) ((core (0 1) *)) | |
178 | 178 | | (equal? 7 8 9)) |
179 | 179 | ? uncaught exception: (illegal-arguments 7 8 9) |
180 | 180 | |
183 | 183 | `pair?` evaluates its argument, then evaluates to `#t` if it is a pair, |
184 | 184 | `#f` otherwise. |
185 | 185 | |
186 | | (robin (0 . 1) (core (0 . 1)) | |
186 | | (robin (0 1) ((core (0 1) *)) | |
187 | 187 | | (pair? ((macro (self args env) (head args)) (a . b)))) |
188 | 188 | = #t |
189 | 189 | |
190 | | (robin (0 . 1) (core (0 . 1)) | |
190 | | (robin (0 1) ((core (0 1) *)) | |
191 | 191 | | (pair? ((macro (self args env) (head args)) (a b c d e f)))) |
192 | 192 | = #t |
193 | 193 | |
194 | | (robin (0 . 1) (core (0 . 1)) | |
194 | | (robin (0 1) ((core (0 1) *)) | |
195 | 195 | | (pair? (pair 4 5))) |
196 | 196 | = #t |
197 | 197 | |
198 | 198 | Symbols are not pairs. |
199 | 199 | |
200 | | (robin (0 . 1) (core (0 . 1)) | |
200 | | (robin (0 1) ((core (0 1) *)) | |
201 | 201 | | (pair? ((macro (self args env) (head args)) b))) |
202 | 202 | = #f |
203 | 203 | |
204 | 204 | The argument to `pair?` may (naturally) be any type, but there must be |
205 | 205 | exactly one argument. |
206 | 206 | |
207 | | (robin (0 . 1) (core (0 . 1)) | |
207 | | (robin (0 1) ((core (0 1) *)) | |
208 | 208 | | (pair? (pair 4 5) (pair 6 7))) |
209 | 209 | ? uncaught exception: (illegal-arguments (pair 4 5) (pair 6 7)) |
210 | 210 | |
213 | 213 | `macro?` evaluates its argument, then evaluates to `#t` if it is a macro |
214 | 214 | (either built-in or user-defined), or `#f` if it is not. |
215 | 215 | |
216 | | (robin (0 . 1) (core (0 . 1)) | |
216 | | (robin (0 1) ((core (0 1) *)) | |
217 | 217 | | (macro? (macro (self args env) args))) |
218 | 218 | = #t |
219 | 219 | |
220 | | (robin (0 . 1) (core (0 . 1)) | |
220 | | (robin (0 1) ((core (0 1) *)) | |
221 | 221 | | (macro? macro)) |
222 | 222 | = #t |
223 | 223 | |
224 | | (robin (0 . 1) (core (0 . 1)) | |
224 | | (robin (0 1) ((core (0 1) *)) | |
225 | 225 | | (macro? ((macro (self args env) (head args)) macro))) |
226 | 226 | = #f |
227 | 227 | |
228 | | (robin (0 . 1) (core (0 . 1)) | |
228 | | (robin (0 1) ((core (0 1) *)) | |
229 | 229 | | (macro? 4/5)) |
230 | 230 | = #f |
231 | 231 | |
232 | 232 | The argument to `macro?` may (naturally) be any type, but there must be |
233 | 233 | exactly one argument. |
234 | 234 | |
235 | | (robin (0 . 1) (core (0 . 1)) | |
235 | | (robin (0 1) ((core (0 1) *)) | |
236 | 236 | | (macro? macro macro)) |
237 | 237 | ? uncaught exception: (illegal-arguments macro macro) |
238 | 238 | |
241 | 241 | `symbol?` evaluates its argument, then evaluates to `#t` if it is a symbol, |
242 | 242 | `#f` otherwise. |
243 | 243 | |
244 | | (robin (0 . 1) (core (0 . 1)) | |
244 | | (robin (0 1) ((core (0 1) *)) | |
245 | 245 | | (symbol? ((macro (s a e) (head a)) this-symbol))) |
246 | 246 | = #t |
247 | 247 | |
248 | 248 | Pairs are not symbols. |
249 | 249 | |
250 | | (robin (0 . 1) (core (0 . 1)) | |
250 | | (robin (0 1) ((core (0 1) *)) | |
251 | 251 | | (symbol? (pair 1 2))) |
252 | 252 | = #f |
253 | 253 | |
254 | 254 | The argument to `symbol?` may (naturally) be any type, but there must be |
255 | 255 | exactly one argument. |
256 | 256 | |
257 | | (robin (0 . 1) (core (0 . 1)) | |
257 | | (robin (0 1) ((core (0 1) *)) | |
258 | 258 | | (symbol? 77 88)) |
259 | 259 | ? uncaught exception: (illegal-arguments 77 88) |
260 | 260 | |
263 | 263 | `boolean?` evaluates its argument, then evaluates to `#t` if it is a |
264 | 264 | boolean value, `#f` otherwise. |
265 | 265 | |
266 | | (robin (0 . 1) (core (0 . 1)) | |
266 | | (robin (0 1) ((core (0 1) *)) | |
267 | 267 | | (boolean? #t)) |
268 | 268 | = #t |
269 | 269 | |
270 | | (robin (0 . 1) (core (0 . 1)) | |
270 | | (robin (0 1) ((core (0 1) *)) | |
271 | 271 | | (boolean? #f)) |
272 | 272 | = #t |
273 | 273 | |
274 | | (robin (0 . 1) (core (0 . 1)) | |
274 | | (robin (0 1) ((core (0 1) *)) | |
275 | 275 | | (boolean? ())) |
276 | 276 | = #f |
277 | 277 | |
278 | 278 | The argument to `symbol?` may (naturally) be any type, but there must be |
279 | 279 | exactly one argument. |
280 | 280 | |
281 | | (robin (0 . 1) (core (0 . 1)) | |
281 | | (robin (0 1) ((core (0 1) *)) | |
282 | 282 | | (boolean? #t #f)) |
283 | 283 | ? uncaught exception: (illegal-arguments #t #f) |
284 | 284 | |
287 | 287 | `number?` evaluates its argument, then evaluates to `#t` if it is a |
288 | 288 | rational number, `#f` otherwise. |
289 | 289 | |
290 | | (robin (0 . 1) (core (0 . 1)) | |
290 | | (robin (0 1) ((core (0 1) *)) | |
291 | 291 | | (number? 5/7)) |
292 | 292 | = #t |
293 | 293 | |
294 | | (robin (0 . 1) (core (0 . 1)) | |
294 | | (robin (0 1) ((core (0 1) *)) | |
295 | 295 | | (number? 0)) |
296 | 296 | = #t |
297 | 297 | |
298 | | (robin (0 . 1) (core (0 . 1)) | |
298 | | (robin (0 1) ((core (0 1) *)) | |
299 | 299 | | (number? ())) |
300 | 300 | = #f |
301 | 301 | |
302 | | (robin (0 . 1) (core (0 . 1)) | |
302 | | (robin (0 1) ((core (0 1) *)) | |
303 | 303 | | (number? #t)) |
304 | 304 | = #f |
305 | 305 | |
306 | 306 | The argument to `number?` may (naturally) be any type, but there must be |
307 | 307 | exactly one argument. |
308 | 308 | |
309 | | (robin (0 . 1) (core (0 . 1)) | |
309 | | (robin (0 1) ((core (0 1) *)) | |
310 | 310 | | (number? 6 4)) |
311 | 311 | ? uncaught exception: (illegal-arguments 6 4) |
312 | 312 | |
316 | 316 | evaluates its second argument to a rational number, then evaluates |
317 | 317 | to the difference between the first and second numbers. |
318 | 318 | |
319 | | (robin (0 . 1) (core (0 . 1)) | |
319 | | (robin (0 1) ((core (0 1) *)) | |
320 | 320 | | (subtract 6 4)) |
321 | 321 | = 2 |
322 | 322 | |
323 | | (robin (0 . 1) (core (0 . 1)) | |
323 | | (robin (0 1) ((core (0 1) *)) | |
324 | 324 | | (subtract 16/15 1/5)) |
325 | 325 | = 13/15 |
326 | 326 | |
327 | | (robin (0 . 1) (core (0 . 1)) | |
327 | | (robin (0 1) ((core (0 1) *)) | |
328 | 328 | | (subtract 1000 8000)) |
329 | 329 | = -7000 |
330 | 330 | |
331 | 331 | Addition may be accomplished by negating the second argument. |
332 | 332 | |
333 | | (robin (0 . 1) (core (0 . 1)) | |
333 | | (robin (0 1) ((core (0 1) *)) | |
334 | 334 | | (subtract 999 (subtract 0 999))) |
335 | 335 | = 1998 |
336 | 336 | |
337 | 337 | `subtract` expects both of its arguments to be numbers. |
338 | 338 | |
339 | | (robin (0 . 1) (core (0 . 1)) | |
339 | | (robin (0 1) ((core (0 1) *)) | |
340 | 340 | | (subtract #f 100)) |
341 | 341 | ? uncaught exception: (expected-number . #f) |
342 | 342 | |
343 | | (robin (0 . 1) (core (0 . 1)) | |
343 | | (robin (0 1) ((core (0 1) *)) | |
344 | 344 | | (subtract 100 ())) |
345 | 345 | ? uncaught exception: (expected-number) |
346 | 346 | |
347 | 347 | `subtract` expects exactly two arguments. |
348 | 348 | |
349 | | (robin (0 . 1) (core (0 . 1)) | |
349 | | (robin (0 1) ((core (0 1) *)) | |
350 | 350 | | (subtract 100 200 300)) |
351 | 351 | ? uncaught exception: (illegal-arguments 100 200 300) |
352 | 352 | |
353 | | (robin (0 . 1) (core (0 . 1)) | |
353 | | (robin (0 1) ((core (0 1) *)) | |
354 | 354 | | (subtract)) |
355 | 355 | ? uncaught exception: (illegal-arguments) |
356 | 356 | |
360 | 360 | evaluates its second argument to a rational number, then evaluates |
361 | 361 | to the ratio between the first and second numbers. |
362 | 362 | |
363 | | (robin (0 . 1) (core (0 . 1)) | |
363 | | (robin (0 1) ((core (0 1) *)) | |
364 | 364 | | (divide 99 11)) |
365 | 365 | = 9 |
366 | 366 | |
367 | | (robin (0 . 1) (core (0 . 1)) | |
367 | | (robin (0 1) ((core (0 1) *)) | |
368 | 368 | | (divide 6 4)) |
369 | 369 | = 3/2 |
370 | 370 | |
371 | | (robin (0 . 1) (core (0 . 1)) | |
371 | | (robin (0 1) ((core (0 1) *)) | |
372 | 372 | | (divide 4 (subtract 0 5))) |
373 | 373 | = -4/5 |
374 | 374 | |
377 | 377 | Addition may be accomplished by taking the reciprocal of the second |
378 | 378 | argument. |
379 | 379 | |
380 | | (robin (0 . 1) (core (0 . 1)) | |
380 | | (robin (0 1) ((core (0 1) *)) | |
381 | 381 | | (divide 123 0)) |
382 | 382 | ? uncaught exception: (division-by-zero . 123) |
383 | 383 | |
384 | 384 | Addition may be accomplished by taking the reciprocal of the second |
385 | 385 | argument. |
386 | 386 | |
387 | | (robin (0 . 1) (core (0 . 1)) | |
387 | | (robin (0 1) ((core (0 1) *)) | |
388 | 388 | | (divide 7 (divide 1 7))) |
389 | 389 | = 49 |
390 | 390 | |
391 | 391 | `divide` expects both of its arguments to be numbers. |
392 | 392 | |
393 | | (robin (0 . 1) (core (0 . 1)) | |
393 | | (robin (0 1) ((core (0 1) *)) | |
394 | 394 | | (divide #f 100)) |
395 | 395 | ? uncaught exception: (expected-number . #f) |
396 | 396 | |
397 | | (robin (0 . 1) (core (0 . 1)) | |
397 | | (robin (0 1) ((core (0 1) *)) | |
398 | 398 | | (divide 100 ())) |
399 | 399 | ? uncaught exception: (expected-number) |
400 | 400 | |
401 | 401 | `divide` expects exactly two arguments. |
402 | 402 | |
403 | | (robin (0 . 1) (core (0 . 1)) | |
403 | | (robin (0 1) ((core (0 1) *)) | |
404 | 404 | | (divide 100 200 300)) |
405 | 405 | ? uncaught exception: (illegal-arguments 100 200 300) |
406 | 406 | |
407 | | (robin (0 . 1) (core (0 . 1)) | |
407 | | (robin (0 1) ((core (0 1) *)) | |
408 | 408 | | (divide)) |
409 | 409 | ? uncaught exception: (illegal-arguments) |
410 | 410 | |
413 | 413 | `floor` evaluates its sole argument to a rational number, then |
414 | 414 | evaluates to the nearest whole number not larger than that rational. |
415 | 415 | |
416 | | (robin (0 . 1) (core (0 . 1)) | |
416 | | (robin (0 1) ((core (0 1) *)) | |
417 | 417 | | (floor 26/5)) |
418 | 418 | = 5 |
419 | 419 | |
420 | | (robin (0 . 1) (core (0 . 1)) | |
420 | | (robin (0 1) ((core (0 1) *)) | |
421 | 421 | | (floor 5)) |
422 | 422 | = 5 |
423 | 423 | |
424 | | (robin (0 . 1) (core (0 . 1)) | |
424 | | (robin (0 1) ((core (0 1) *)) | |
425 | 425 | | (floor (subtract 0 1/2))) |
426 | 426 | = -1 |
427 | 427 | |
428 | | (robin (0 . 1) (core (0 . 1)) | |
428 | | (robin (0 1) ((core (0 1) *)) | |
429 | 429 | | (floor 100 200 300)) |
430 | 430 | ? uncaught exception: (illegal-arguments 100 200 300) |
431 | 431 | |
432 | | (robin (0 . 1) (core (0 . 1)) | |
432 | | (robin (0 1) ((core (0 1) *)) | |
433 | 433 | | (floor)) |
434 | 434 | ? uncaught exception: (illegal-arguments) |
435 | 435 | |
439 | 439 | evaluates to 0 if that number is 0, 1 if that number is positive, or |
440 | 440 | -1 if that number is negative. |
441 | 441 | |
442 | | (robin (0 . 1) (core (0 . 1)) | |
442 | | (robin (0 1) ((core (0 1) *)) | |
443 | 443 | | (sign 26/5)) |
444 | 444 | = 1 |
445 | 445 | |
446 | | (robin (0 . 1) (core (0 . 1)) | |
446 | | (robin (0 1) ((core (0 1) *)) | |
447 | 447 | | (sign 0)) |
448 | 448 | = 0 |
449 | 449 | |
450 | | (robin (0 . 1) (core (0 . 1)) | |
450 | | (robin (0 1) ((core (0 1) *)) | |
451 | 451 | | (sign (subtract 0 200))) |
452 | 452 | = -1 |
453 | 453 | |
454 | | (robin (0 . 1) (core (0 . 1)) | |
454 | | (robin (0 1) ((core (0 1) *)) | |
455 | 455 | | (sign 100 200 300)) |
456 | 456 | ? uncaught exception: (illegal-arguments 100 200 300) |
457 | 457 | |
458 | | (robin (0 . 1) (core (0 . 1)) | |
458 | | (robin (0 1) ((core (0 1) *)) | |
459 | 459 | | (sign)) |
460 | 460 | ? uncaught exception: (illegal-arguments) |
461 | 461 | |
469 | 469 | sake of purity, that dependency should be removed (but the tests |
470 | 470 | will look awful.) |
471 | 471 | |
472 | | (robin (0 . 1) (small (0 . 1)) | |
472 | | (robin (0 1) ((small (0 1) *)) | |
473 | 473 | | (eval (env) (literal (pair (literal a) (literal b))))) |
474 | 474 | = (a . b) |
475 | 475 | |
476 | | (robin (0 . 1) (small (0 . 1)) | |
476 | | (robin (0 1) ((small (0 1) *)) | |
477 | 477 | | (eval () (literal (pair (literal a) (literal b))))) |
478 | 478 | ? uncaught exception: (unbound-identifier . pair) |
479 | 479 | |
480 | | (robin (0 . 1) (small (0 . 1)) | |
480 | | (robin (0 1) ((small (0 1) *)) | |
481 | 481 | | (bind bindings (pair |
482 | 482 | | (pair (literal same) equal?) |
483 | 483 | | (pair (pair (literal x) #f) (literal ()))) |
488 | 488 | alist passed to `eval`, the one closer to the front of the alist takes |
489 | 489 | precedence. |
490 | 490 | |
491 | | (robin (0 . 1) (small (0 . 1)) | |
491 | | (robin (0 1) ((small (0 1) *)) | |
492 | 492 | | (bind bindings (pair |
493 | 493 | | (pair (literal foo) (literal yes)) |
494 | 494 | | (pair (pair (literal foo) (literal no)) |
500 | 500 | environment, however, subsequent evaluation will fail when it |
501 | 501 | tries to look up things in that environment. |
502 | 502 | |
503 | | (robin (0 . 1) (small (0 . 1)) | |
503 | | (robin (0 1) ((small (0 1) *)) | |
504 | 504 | | (eval 103 (literal (pair (literal a) (literal b))))) |
505 | 505 | ? uncaught exception: (expected-pair . 103) |
506 | 506 | |
507 | 507 | Evaluation expects the contents of the list which makes up the |
508 | 508 | environment to be pairs. |
509 | 509 | |
510 | | (robin (0 . 1) (small (0 . 1)) | |
510 | | (robin (0 1) ((small (0 1) *)) | |
511 | 511 | | (eval (pair #f ()) (literal (pair (literal a) (literal b))))) |
512 | 512 | ? uncaught exception: (expected-pair . #f) |
513 | 513 | |
514 | 514 | Evaluation expects the head of each pair in the list which makes up the |
515 | 515 | environment to be a symbol. |
516 | 516 | |
517 | | (robin (0 . 1) (small (0 . 1)) | |
517 | | (robin (0 1) ((small (0 1) *)) | |
518 | 518 | | (eval (pair (pair 7 #f) ()) (literal (pair (literal a) (literal b))))) |
519 | 519 | ? uncaught exception: (expected-symbol . 7) |
520 | 520 | |
521 | 521 | `eval` expects exactly two arguments. |
522 | 522 | |
523 | | (robin (0 . 1) (core (0 . 1)) | |
523 | | (robin (0 1) ((core (0 1) *)) | |
524 | 524 | | (eval)) |
525 | 525 | ? uncaught exception: (illegal-arguments) |
526 | 526 | |
527 | | (robin (0 . 1) (core (0 . 1)) | |
527 | | (robin (0 1) ((core (0 1) *)) | |
528 | 528 | | (eval 4 5 6)) |
529 | 529 | ? uncaught exception: (illegal-arguments 4 5 6) |
530 | 530 | |
548 | 548 | `literal`, in fact, can be defined as a macro, and it is one of the |
549 | 549 | simplest possible macros that can be written: |
550 | 550 | |
551 | | (robin (0 . 1) (core (0 . 1)) | |
551 | | (robin (0 1) ((core (0 1) *)) | |
552 | 552 | | ((macro (self args env) (head args)) (why hello there))) |
553 | 553 | = (why hello there) |
554 | 554 | |
556 | 556 | macro is defined will still be in force when the macro is applied, |
557 | 557 | even if they are no longer lexically in scope. |
558 | 558 | |
559 | | (robin (0 . 1) (small (0 . 1)) | |
559 | | (robin (0 1) ((small (0 1) *)) | |
560 | 560 | | ((let |
561 | 561 | | ((a (literal these-are)) |
562 | 562 | | (m (macro (self args env) (pair a args)))) |
565 | 565 | |
566 | 566 | Macros can return macros. |
567 | 567 | |
568 | | (robin (0 . 1) (small (0 . 1)) | |
568 | | (robin (0 1) ((small (0 1) *)) | |
569 | 569 | | (let |
570 | 570 | | ((mk (macro (self argsa env) |
571 | 571 | | (macro (self argsb env) |
576 | 576 | |
577 | 577 | Arguments to macros shadow any other bindings in effect. |
578 | 578 | |
579 | | (robin (0 . 1) (small (0 . 1)) | |
579 | | (robin (0 1) ((small (0 1) *)) | |
580 | 580 | | (let |
581 | 581 | | ((args (literal a)) |
582 | 582 | | (b (macro (self args env) (pair args args)))) |
591 | 591 | sake of purity, that dependency should be removed (but the tests |
592 | 592 | will look awful.) |
593 | 593 | |
594 | | (robin (0 . 1) (small (0 . 1)) | |
594 | | (robin (0 1) ((small (0 1) *)) | |
595 | 595 | | (bind qqq |
596 | 596 | | (macro (self args env) |
597 | 597 | | (if (equal? args ()) |
601 | 601 | | (bind b 1 (bind d 4 (qqq b c d))))) |
602 | 602 | = (0 . 0) |
603 | 603 | |
604 | | (robin (0 . 1) (small (0 . 1)) | |
604 | | (robin (0 1) ((small (0 1) *)) | |
605 | 605 | | (bind qqq |
606 | 606 | | (macro (self args env) |
607 | 607 | | (if (equal? args ()) |
613 | 613 | |
614 | 614 | Your recursive `macro` application doesn't have to be tail-recursive. |
615 | 615 | |
616 | | (robin (0 . 1) (small (0 . 1)) | |
616 | | (robin (0 1) ((small (0 1) *)) | |
617 | 617 | | (bind make-env |
618 | 618 | | (macro (self args env) |
619 | 619 | | (if (equal? args ()) |
626 | 626 | |
627 | 627 | `macro` expects exactly two arguments. |
628 | 628 | |
629 | | (robin (0 . 1) (core (0 . 1)) | |
629 | | (robin (0 1) ((core (0 1) *)) | |
630 | 630 | | ((macro (self args env)) (why hello there))) |
631 | 631 | ? uncaught exception: (illegal-arguments (self args env)) |
632 | 632 | |
633 | | (robin (0 . 1) (core (0 . 1)) | |
633 | | (robin (0 1) ((core (0 1) *)) | |
634 | 634 | | ((macro (self args env) pair pair) (why hello there))) |
635 | 635 | ? uncaught exception: (illegal-arguments (self args env) pair pair) |
636 | 636 | |
637 | 637 | `macro` expects its first argument to be a list of exactly three |
638 | 638 | symbols. |
639 | 639 | |
640 | | (robin (0 . 1) (core (0 . 1)) | |
640 | | (robin (0 1) ((core (0 1) *)) | |
641 | 641 | | ((macro 100 pair) (why hello there))) |
642 | 642 | ? uncaught exception: (illegal-arguments 100 pair) |
643 | 643 | |
644 | | (robin (0 . 1) (core (0 . 1)) | |
644 | | (robin (0 1) ((core (0 1) *)) | |
645 | 645 | | ((macro (self args) pair) (why hello there))) |
646 | 646 | ? uncaught exception: (illegal-arguments (self args) pair) |
647 | 647 | |
648 | | (robin (0 . 1) (core (0 . 1)) | |
648 | | (robin (0 1) ((core (0 1) *)) | |
649 | 649 | | ((macro (self args env foo) pair) (why hello there))) |
650 | 650 | ? uncaught exception: (illegal-arguments (self args env foo) pair) |
651 | 651 | |
652 | | (robin (0 . 1) (core (0 . 1)) | |
652 | | (robin (0 1) ((core (0 1) *)) | |
653 | 653 | | ((macro (self args 99) pair) (why hello there))) |
654 | 654 | ? uncaught exception: (illegal-arguments (self args 99) pair) |
655 | 655 | |
666 | 666 | refers to the exception that triggered it, but this is not a strict |
667 | 667 | requirement. |
668 | 668 | |
669 | | (robin (0 . 1) (core (0 . 1)) | |
669 | | (robin (0 1) ((core (0 1) *)) | |
670 | 670 | | (raise 999999)) |
671 | 671 | ? uncaught exception: 999999 |
672 | 672 | |
673 | 673 | `raise`'s single argument may be any kind of value, but `raise` expects |
674 | 674 | exactly one argument. |
675 | 675 | |
676 | | (robin (0 . 1) (core (0 . 1)) | |
676 | | (robin (0 1) ((core (0 1) *)) | |
677 | 677 | | (raise)) |
678 | 678 | ? uncaught exception: (illegal-arguments) |
679 | 679 | |
680 | | (robin (0 . 1) (core (0 . 1)) | |
680 | | (robin (0 1) ((core (0 1) *)) | |
681 | 681 | | (raise 2 3 4)) |
682 | 682 | ? uncaught exception: (illegal-arguments 2 3 4) |
683 | 683 | |
685 | 685 | |
686 | 686 | `with` attaches metadata to a value. |
687 | 687 | |
688 | | (robin (0 . 1) (core (0 . 1)) | |
688 | | (robin (0 1) ((core (0 1) *)) | |
689 | 689 | | (with #t 5)) |
690 | 690 | = 5 |
691 | 691 | |
692 | 692 | Passing values with metadata attached shouldn't break any of the core |
693 | 693 | macros. |
694 | 694 | |
695 | | (robin (0 . 1) (core (0 . 1)) | |
695 | | (robin (0 1) ((core (0 1) *)) | |
696 | 696 | | (head (with #t (pair 1 2)))) |
697 | 697 | = 1 |
698 | 698 | |
699 | | (robin (0 . 1) (core (0 . 1)) | |
699 | | (robin (0 1) ((core (0 1) *)) | |
700 | 700 | | (tail (with #t (pair 1 2)))) |
701 | 701 | = 2 |
702 | 702 | |
703 | | (robin (0 . 1) (core (0 . 1)) | |
703 | | (robin (0 1) ((core (0 1) *)) | |
704 | 704 | | (pair (with #t 1) (with #t 2))) |
705 | 705 | = (1 . 2) |
706 | 706 | |
707 | | (robin (0 . 1) (core (0 . 1)) | |
707 | | (robin (0 1) ((core (0 1) *)) | |
708 | 708 | | (pair (with #t 1) (with #t 2))) |
709 | 709 | = (1 . 2) |
710 | 710 | |
711 | | (robin (0 . 1) (core (0 . 1)) | |
711 | | (robin (0 1) ((core (0 1) *)) | |
712 | 712 | | (if (with #t #t) (with #t 2) (with #t 3))) |
713 | 713 | = 2 |
714 | 714 | |
715 | | (robin (0 . 1) (core (0 . 1)) | |
715 | | (robin (0 1) ((core (0 1) *)) | |
716 | 716 | | (if (with 777 #f) (with #t 2) (with #t 3))) |
717 | 717 | = 3 |
718 | 718 | |
719 | | (robin (0 . 1) (core (0 . 1)) | |
719 | | (robin (0 1) ((core (0 1) *)) | |
720 | 720 | | (equal? (with #t 4) (with #t 4))) |
721 | 721 | = #t |
722 | 722 | |
723 | | (robin (0 . 1) (core (0 . 1)) | |
723 | | (robin (0 1) ((core (0 1) *)) | |
724 | 724 | | (pair? (with #t (pair 2 3)))) |
725 | 725 | = #t |
726 | 726 | |
727 | | (robin (0 . 1) (core (0 . 1)) | |
727 | | (robin (0 1) ((core (0 1) *)) | |
728 | 728 | | (number? (with #t 3))) |
729 | 729 | = #t |
730 | 730 | |
731 | | (robin (0 . 1) (small (0 . 1)) | |
731 | | (robin (0 1) ((small (0 1) *)) | |
732 | 732 | | (symbol? (with #t (literal x)))) |
733 | 733 | = #t |
734 | 734 | |
735 | | (robin (0 . 1) (core (0 . 1)) | |
735 | | (robin (0 1) ((core (0 1) *)) | |
736 | 736 | | (macro? (with #t (macro (self args env) args)))) |
737 | 737 | = #t |
738 | 738 | |
739 | | (robin (0 . 1) (core (0 . 1)) | |
739 | | (robin (0 1) ((core (0 1) *)) | |
740 | 740 | | (boolean? (with #t #t))) |
741 | 741 | = #t |
742 | 742 | |
743 | | (robin (0 . 1) (core (0 . 1)) | |
743 | | (robin (0 1) ((core (0 1) *)) | |
744 | 744 | | ((with #t (macro (self args env) args)) foo bar baz)) |
745 | 745 | = (foo bar baz) |
746 | 746 | |
747 | | (robin (0 . 1) (core (0 . 1)) | |
747 | | (robin (0 1) ((core (0 1) *)) | |
748 | 748 | | (subtract (with #t 0) (with #f 5))) |
749 | 749 | = -5 |
750 | 750 | |
751 | | (robin (0 . 1) (core (0 . 1)) | |
751 | | (robin (0 1) ((core (0 1) *)) | |
752 | 752 | | (divide (with #t 1) (with #f 5))) |
753 | 753 | = 1/5 |
754 | 754 | |
755 | | (robin (0 . 1) (core (0 . 1)) | |
755 | | (robin (0 1) ((core (0 1) *)) | |
756 | 756 | | (sign (with #t 1))) |
757 | 757 | = 1 |
758 | 758 | |
759 | | (robin (0 . 1) (core (0 . 1)) | |
759 | | (robin (0 1) ((core (0 1) *)) | |
760 | 760 | | (floor (with #t 3/2))) |
761 | 761 | = 1 |
762 | 762 | |
763 | 763 | Testing for equality ignores metadata. |
764 | 764 | |
765 | | (robin (0 . 1) (core (0 . 1)) | |
765 | | (robin (0 1) ((core (0 1) *)) | |
766 | 766 | | (equal? (with #t 4) 4)) |
767 | 767 | = #t |
768 | 768 | |
769 | | (robin (0 . 1) (core (0 . 1)) | |
769 | | (robin (0 1) ((core (0 1) *)) | |
770 | 770 | | (equal? 4 (with #t 4))) |
771 | 771 | = #t |
772 | 772 | |
773 | | (robin (0 . 1) (core (0 . 1)) | |
773 | | (robin (0 1) ((core (0 1) *)) | |
774 | 774 | | (equal? (with #t 4) (with #f 4))) |
775 | 775 | = #t |
776 | 776 | |
777 | | (robin (0 . 1) (core (0 . 1)) | |
777 | | (robin (0 1) ((core (0 1) *)) | |
778 | 778 | | (equal? (with #t 4) (with #t 5))) |
779 | 779 | = #f |
780 | 780 | |
782 | 782 | |
783 | 783 | `has?` checks if a value has a given metadata. |
784 | 784 | |
785 | | (robin (0 . 1) (core (0 . 1)) | |
785 | | (robin (0 1) ((core (0 1) *)) | |
786 | 786 | | (has? #t 4)) |
787 | 787 | = #f |
788 | 788 | |
789 | | (robin (0 . 1) (core (0 . 1)) | |
789 | | (robin (0 1) ((core (0 1) *)) | |
790 | 790 | | (has? #t (with #t 4))) |
791 | 791 | = #t |
792 | 792 | |
793 | | (robin (0 . 1) (core (0 . 1)) | |
793 | | (robin (0 1) ((core (0 1) *)) | |
794 | 794 | | (has? #t (head (pair (with #t 4) 5)))) |
795 | 795 | = #t |
796 | 796 | |
797 | 797 | Binding retains metatdata. |
798 | 798 | |
799 | | (robin (0 . 1) (small (0 . 1)) | |
799 | | (robin (0 1) ((small (0 1) *)) | |
800 | 800 | | (bind q (with (literal gee) 77) |
801 | 801 | | (has? (literal gee) q))) |
802 | 802 | = #t |
803 | 803 | |
804 | 804 | Metadata is retained in macros. |
805 | 805 | |
806 | | (robin (0 . 1) (small (0 . 1)) | |
806 | | (robin (0 1) ((small (0 1) *)) | |
807 | 807 | | (bind whee |
808 | 808 | | (macro (self args env) |
809 | 809 | | (pair (head (head env)) |
39 | 39 | be written to the standard output, and an `ok` message sent back to the |
40 | 40 | sending process as a confirmation. |
41 | 41 | |
42 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1) crude-io (0 . 1)) | |
42 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *) (crude-io (0 1) *)) | |
43 | 43 | | (call! crude-output write (literal hello-world) reply reply)) |
44 | 44 | = hello-world |
45 | 45 | = ok |
53 | 53 | implementation need not write the result of the main process to the |
54 | 54 | standard output. |
55 | 55 | |
56 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1) crude-io (0 . 1)) | |
56 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *) (crude-io (0 1) *)) | |
57 | 57 | | (call! crude-output write (literal hello-world) reply 0)) |
58 | 58 | = hello-world |
59 | 59 | |
61 | 61 | message will be formatted as a textual S-expression, and written out on |
62 | 62 | its own line. |
63 | 63 | |
64 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1) crude-io (0 . 1)) | |
64 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *) (crude-io (0 1) *)) | |
65 | 65 | | (call! crude-output write (literal hello) x |
66 | 66 | | (call! crude-output write (literal (world 1 2 3)) y |
67 | 67 | | 0))) |
90 | 90 | `crude-input` can be subscribed to, and the subscriber will receive |
91 | 91 | messages when input occurs. |
92 | 92 | |
93 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1) crude-io (0 . 1)) | |
93 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *) (crude-io (0 1) *)) | |
94 | 94 | | (call! crude-input subscribe () x |
95 | 95 | | (recv! entered |
96 | 96 | | (pair (literal i-got) entered)))) |
100 | 100 | |
101 | 101 | Arbitrary S-expressions may occur on each line; they are parsed. |
102 | 102 | |
103 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1) crude-io (0 . 1)) | |
103 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *) (crude-io (0 1) *)) | |
104 | 104 | | (call! crude-input subscribe () x |
105 | 105 | | (recv! entered |
106 | 106 | | (pair (literal i-got) entered)))) |
110 | 110 | |
111 | 111 | Multiple lines of text may be input, and multiple messages will be sent. |
112 | 112 | |
113 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1) crude-io (0 . 1)) | |
113 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *) (crude-io (0 1) *)) | |
114 | 114 | | (bind input-loop |
115 | 115 | | (fun (self) |
116 | 116 | | (recv! entered |
129 | 129 | If an S-expression on a given line cannot be parsed, no message will be |
130 | 130 | sent. |
131 | 131 | |
132 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1) crude-io (0 . 1)) | |
132 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *) (crude-io (0 1) *)) | |
133 | 133 | | (bind input-loop |
134 | 134 | | (fun (self) |
135 | 135 | | (recv! entered |
27 | 27 | of capabilities. Each capability is (for now) a symbol, which refers to |
28 | 28 | a required capability of the device. |
29 | 29 | |
30 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1) device (0 . 1)) | |
30 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *) (device (0 1) *)) | |
31 | 31 | | (acquire! (console (ascii colour addressable) |
32 | 32 | | foo ()) |
33 | 33 | | (pair (pid? console) (pid? foo)))) |
43 | 43 | the device that it will no longer be used by this process. Subsequent |
44 | 44 | messages sent to the device pid from this process will be ignored. |
45 | 45 | |
46 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1) device (0 . 1)) | |
46 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *) (device (0 1) *)) | |
47 | 47 | | (acquire! (console (ascii colour addressable)) |
48 | 48 | | (release! console |
49 | 49 | | 123))) |
16 | 16 | `env?` evaluates its single argument, and evaluates to `#t` if |
17 | 17 | and only if it is a well-formed binding alist. |
18 | 18 | |
19 | | (robin (0 . 1) (small (0 . 1) env (0 . 1)) | |
19 | | (robin (0 1) ((small (0 1) *) (env (0 1) *)) | |
20 | 20 | | (env? (literal ((a . 1) (b . 2) (c . 3))))) |
21 | 21 | = #t |
22 | 22 | |
23 | | (robin (0 . 1) (small (0 . 1) env (0 . 1)) | |
23 | | (robin (0 1) ((small (0 1) *) (env (0 1) *)) | |
24 | 24 | | (env? (literal ((a . 1) (999 . 2) (c . 3))))) |
25 | 25 | = #f |
26 | 26 | |
27 | | (robin (0 . 1) (small (0 . 1) env (0 . 1)) | |
27 | | (robin (0 1) ((small (0 1) *) (env (0 1) *)) | |
28 | 28 | | (env? (literal ((a . 1) (b . 2) . c)))) |
29 | 29 | = #f |
30 | 30 | |
31 | | (robin (0 . 1) (small (0 . 1) env (0 . 1)) | |
31 | | (robin (0 1) ((small (0 1) *) (env (0 1) *)) | |
32 | 32 | | (env? 7)) |
33 | 33 | = #f |
34 | 34 | |
35 | | (robin (0 . 1) (small (0 . 1) env (0 . 1)) | |
35 | | (robin (0 1) ((small (0 1) *) (env (0 1) *)) | |
36 | 36 | | (env? (env))) |
37 | 37 | = #t |
38 | 38 | |
41 | 41 | `unbind` removes the given identifier from the environment and evaluates its |
42 | 42 | second argument in that reduced environment. |
43 | 43 | |
44 | | (robin (0 . 1) (small (0 . 1) env (0 . 1)) | |
44 | | (robin (0 1) ((small (0 1) *) (env (0 1) *)) | |
45 | 45 | | (unbind if (if #t (literal x) (literal y)))) |
46 | 46 | ? uncaught exception: (unbound-identifier . if) |
47 | 47 | |
48 | 48 | If the identifier doesn't exist in the environment, no change is made to |
49 | 49 | the environment. |
50 | 50 | |
51 | | (robin (0 . 1) (small (0 . 1) env (0 . 1)) | |
51 | | (robin (0 1) ((small (0 1) *) (env (0 1) *)) | |
52 | 52 | | (unbind yog-sothoth (if #t (literal x) (literal y)))) |
53 | 53 | = x |
54 | 54 | |
56 | 56 | identifier has several definitions that are shadowed, none of them will be |
57 | 57 | in effect. |
58 | 58 | |
59 | | (robin (0 . 1) (small (0 . 1) env (0 . 1)) | |
59 | | (robin (0 1) ((small (0 1) *) (env (0 1) *)) | |
60 | 60 | | (let ((x 7)) |
61 | 61 | | (let ((x 8)) |
62 | 62 | | (unbind x |
69 | 69 | its second argument in an environment where all bindings *except* those |
70 | 70 | for the listed identifiers have been unbound. |
71 | 71 | |
72 | | (robin (0 . 1) (small (0 . 1) env (0 . 1)) | |
72 | | (robin (0 1) ((small (0 1) *) (env (0 1) *)) | |
73 | 73 | | (sandbox (pair tail) |
74 | 74 | | (tail (pair 8 9)))) |
75 | 75 | = 9 |
76 | 76 | |
77 | | (robin (0 . 1) (small (0 . 1) env (0 . 1)) | |
77 | | (robin (0 1) ((small (0 1) *) (env (0 1) *)) | |
78 | 78 | | (sandbox (pair tail) |
79 | 79 | | (head (pair 8 9)))) |
80 | 80 | ? uncaught exception: (unbound-identifier . head) |
94 | 94 | Note: the order of the bindings in the binding alist isn't guaranteed; |
95 | 95 | these tests should be rewritten to search the resulting alist. |
96 | 96 | |
97 | | (robin (0 . 1) (small (0 . 1) env (0 . 1)) | |
97 | | (robin (0 1) ((small (0 1) *) (env (0 1) *)) | |
98 | 98 | | (let ((a 1) (b 2)) |
99 | 99 | | (export a b))) |
100 | 100 | = ((b . 2) (a . 1)) |
101 | 101 | |
102 | | (robin (0 . 1) (small (0 . 1) env (0 . 1)) | |
102 | | (robin (0 1) ((small (0 1) *) (env (0 1) *)) | |
103 | 103 | | (export pair tail)) |
104 | 104 | = ((tail . (builtin tail)) (pair . (builtin pair))) |
105 | 105 | |
109 | 109 | for the given identifier; previously shadowed bindings, if any exist, |
110 | 110 | will be visible instead. |
111 | 111 | |
112 | | (robin (0 . 1) (small (0 . 1) env (0 . 1)) | |
112 | | (robin (0 1) ((small (0 1) *) (env (0 1) *)) | |
113 | 113 | | (unshadow yog-sothoth (if #t (literal x) (literal y)))) |
114 | 114 | = x |
115 | 115 | |
116 | | (robin (0 . 1) (small (0 . 1) env (0 . 1)) | |
116 | | (robin (0 1) ((small (0 1) *) (env (0 1) *)) | |
117 | 117 | | (unshadow if (if #t (literal x) (literal y)))) |
118 | 118 | ? uncaught exception: (unbound-identifier . if) |
119 | 119 | |
120 | | (robin (0 . 1) (small (0 . 1) env (0 . 1)) | |
120 | | (robin (0 1) ((small (0 1) *) (env (0 1) *)) | |
121 | 121 | | (bind if (literal what) |
122 | 122 | | (unshadow if (if #t (literal x) (literal y))))) |
123 | 123 | = x |
124 | 124 | |
125 | | (robin (0 . 1) (small (0 . 1) env (0 . 1)) | |
125 | | (robin (0 1) ((small (0 1) *) (env (0 1) *)) | |
126 | 126 | | (bind q 400 |
127 | 127 | | (unshadow q q))) |
128 | 128 | ? uncaught exception: (unbound-identifier . q) |
129 | 129 | |
130 | | (robin (0 . 1) (small (0 . 1) env (0 . 1)) | |
130 | | (robin (0 1) ((small (0 1) *) (env (0 1) *)) | |
131 | 131 | | (bind q 200 |
132 | 132 | | (bind q 400 |
133 | 133 | | (unshadow q q)))) |
134 | 134 | = 200 |
135 | 135 | |
136 | | (robin (0 . 1) (small (0 . 1) env (0 . 1)) | |
136 | | (robin (0 1) ((small (0 1) *) (env (0 1) *)) | |
137 | 137 | | (bind q 100 |
138 | 138 | | (bind q 200 |
139 | 139 | | (bind q 400 |
140 | 140 | | (unshadow q (unshadow q q)))))) |
141 | 141 | = 100 |
142 | 142 | |
143 | | (robin (0 . 1) (small (0 . 1) env (0 . 1)) | |
143 | | (robin (0 1) ((small (0 1) *) (env (0 1) *)) | |
144 | 144 | | (let ((q 100) |
145 | 145 | | (q 200) |
146 | 146 | | (q 400)) |
158 | 158 | this module re-exports the macro `env` from `core`, and `bind` and `let` |
159 | 159 | from `small`. |
160 | 160 | |
161 | | (robin (0 . 1) (env (0 . 1)) | |
161 | | (robin (0 1) ((env (0 1) *)) | |
162 | 162 | | (env? (env))) |
163 | 163 | = #t |
164 | 164 | |
165 | | (robin (0 . 1) (env (0 . 1)) | |
165 | | (robin (0 1) ((env (0 1) *)) | |
166 | 166 | | (bind a 1 a)) |
167 | 167 | = 1 |
168 | 168 | |
169 | | (robin (0 . 1) (env (0 . 1)) | |
169 | | (robin (0 1) ((env (0 1) *)) | |
170 | 170 | | (let ((a 7) (b a)) b)) |
171 | 171 | = 7 |
25 | 25 | first argument of `catch`, and the second argument of `catch` is |
26 | 26 | evaluated in that new environment. |
27 | 27 | |
28 | | (robin (0 . 1) (small (0 . 1) exception (0 . 1)) | |
28 | | (robin (0 1) ((pure (0 1) *) (exception (0 1) *)) | |
29 | 29 | | (catch error (pair error #f) |
30 | 30 | | (raise (literal (nasty-value . 999999))))) |
31 | 31 | = ((nasty-value . 999999) . #f) |
32 | 32 | |
33 | 33 | `catch` can catch exceptions raised by core macros. |
34 | 34 | |
35 | | (robin (0 . 1) (small (0 . 1) exception (0 . 1)) | |
35 | | (robin (0 1) ((pure (0 1) *) (exception (0 1) *)) | |
36 | 36 | | (catch error (pair error 5) |
37 | 37 | | (head #f))) |
38 | 38 | = ((expected-pair . #f) . 5) |
39 | 39 | |
40 | 40 | The innermost `catch` will catch the exception. |
41 | 41 | |
42 | | (robin (0 . 1) (small (0 . 1) exception (0 . 1)) | |
42 | | (robin (0 1) ((pure (0 1) *) (exception (0 1) *)) | |
43 | 43 | | (catch error (pair error 5) |
44 | 44 | | (catch error (pair error 9) |
45 | 45 | | (head #f)))) |
48 | 48 | An exception raised from within an exception handler is |
49 | 49 | caught by the next innermost exception handler. |
50 | 50 | |
51 | | (robin (0 . 1) (small (0 . 1) exception (0 . 1)) | |
51 | | (robin (0 1) ((pure (0 1) *) (exception (0 1) *)) | |
52 | 52 | | (catch error (pair error 5) |
53 | 53 | | (catch error (pair error 9) |
54 | 54 | | (catch error (raise (pair error error)) |
57 | 57 | |
58 | 58 | `catch` expects its first argument to be an identifier. |
59 | 59 | |
60 | | (robin (0 . 1) (small (0 . 1) exception (0 . 1)) | |
60 | | (robin (0 1) ((pure (0 1) *) (exception (0 1) *)) | |
61 | 61 | | (catch #f 23 (head #f))) |
62 | 62 | ? uncaught exception: (illegal-arguments #f 23 (head #f)) |
63 | 63 | |
64 | 64 | `catch` expects exactly three arguments. |
65 | 65 | |
66 | | (robin (0 . 1) (small (0 . 1) exception (0 . 1)) | |
66 | | (robin (0 1) ((pure (0 1) *) (exception (0 1) *)) | |
67 | 67 | | (catch error error)) |
68 | 68 | ? uncaught exception: (illegal-arguments error error) |
69 | 69 | |
70 | | (robin (0 . 1) (small (0 . 1) exception (0 . 1)) | |
70 | | (robin (0 1) ((pure (0 1) *) (exception (0 1) *)) | |
71 | 71 | | (catch error error (head #f) 23)) |
72 | 72 | ? uncaught exception: (illegal-arguments error error (head #f) 23) |
73 | 73 | |
76 | 76 | Because it would be reasonable to find it here by categorization, this |
77 | 77 | module re-exports the macro `raise` from `core`. |
78 | 78 | |
79 | | (robin (0 . 1) (exception (0 . 1)) | |
79 | | (robin (0 1) ((exception (0 1) *)) | |
80 | 80 | | (catch error error (raise 799))) |
81 | 81 | = 799 |
15 | 15 | `list` is a macro which evaluates each of its arguments, and evaluates to a |
16 | 16 | (proper) list containing each of the results, in the same order. |
17 | 17 | |
18 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
18 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
19 | 19 | | (list 1 2 3 4 5)) |
20 | 20 | = (1 2 3 4 5) |
21 | 21 | |
22 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
22 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
23 | 23 | | (list (pair 2 3) (pair 6 7))) |
24 | 24 | = ((2 . 3) (6 . 7)) |
25 | 25 | |
26 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
26 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
27 | 27 | | (list 1 2 3 4 . 5)) |
28 | 28 | ? uncaught exception: (expected-pair . 5) |
29 | 29 | |
30 | 30 | `list` need not have any arguments at all; the result is the empty list. |
31 | 31 | |
32 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
32 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
33 | 33 | | (list)) |
34 | 34 | = () |
35 | 35 | |
38 | 38 | `empty?` evaluates its single argument, and evaluates to `#t` if that value |
39 | 39 | is the empty list, `#f` otherwise. |
40 | 40 | |
41 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
41 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
42 | 42 | | (empty? (literal symbol))) |
43 | 43 | = #f |
44 | 44 | |
45 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
45 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
46 | 46 | | (empty? ())) |
47 | 47 | = #t |
48 | 48 | |
49 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
49 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
50 | 50 | | (empty? (list 1 2 3))) |
51 | 51 | = #f |
52 | 52 | |
55 | 55 | `list?` evaluates its single argument, and evaluates to `#t` if that value |
56 | 56 | is a proper list, `#f` otherwise. |
57 | 57 | |
58 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
58 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
59 | 59 | | (list? (literal symbol))) |
60 | 60 | = #f |
61 | 61 | |
62 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
62 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
63 | 63 | | (list? ())) |
64 | 64 | = #t |
65 | 65 | |
66 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
66 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
67 | 67 | | (list? (literal (a b c)))) |
68 | 68 | = #t |
69 | 69 | |
70 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
70 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
71 | 71 | | (list? (pair 1 2))) |
72 | 72 | = #f |
73 | 73 | |
74 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
74 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
75 | 75 | | (list? (literal (a b c . d)))) |
76 | 76 | = #f |
77 | 77 | |
82 | 82 | the macro to each element of the given list. The macro is generally assumed |
83 | 83 | to be a one-argument function. |
84 | 84 | |
85 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
85 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
86 | 86 | | (map (fun (x) (list x)) (literal (three dog night)))) |
87 | 87 | = ((three) (dog) (night)) |
88 | 88 | |
89 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
89 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
90 | 90 | | (map (fun (x) (list x)) (literal (three dog . night)))) |
91 | 91 | ? uncaught exception: (expected-pair . night) |
92 | 92 | |
94 | 94 | very productive. (Also, it exposes the implementation of `map`, so this |
95 | 95 | is not a very good test.) |
96 | 96 | |
97 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
97 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
98 | 98 | | (map (macro (self args env) args) (literal (three dog night)))) |
99 | 99 | = (((head li)) ((head li)) ((head li))) |
100 | 100 | |
110 | 110 | the second argument. `fold` evaluates to the result of the the final |
111 | 111 | application of the function. |
112 | 112 | |
113 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
113 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
114 | 114 | | (fold (fun (x a) x) () (literal (three dog night)))) |
115 | 115 | = night |
116 | 116 | |
117 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
117 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
118 | 118 | | (fold (fun (x a) a) 541 (literal (archie moffam)))) |
119 | 119 | = 541 |
120 | 120 | |
121 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
121 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
122 | 122 | | (fold (fun (x a) (pair a x)) () (literal (three dog night)))) |
123 | 123 | = (((() . three) . dog) . night) |
124 | 124 | |
125 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
125 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
126 | 126 | | (fold (fun (x a) a) 1/2 (literal (three dog . night)))) |
127 | 127 | ? uncaught exception: (expected-pair . night) |
128 | 128 | |
129 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
129 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
130 | 130 | | (fold 1/2 (fun (x a) a) (literal (three dog night)))) |
131 | 131 | ? uncaught exception: (inapplicable-object . 1/2) |
132 | 132 | |
136 | 136 | is the same as the given list in every respect except that the order of |
137 | 137 | the elements is reversed. |
138 | 138 | |
139 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
139 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
140 | 140 | | (reverse (literal (1 2 3 4 5)))) |
141 | 141 | = (5 4 3 2 1) |
142 | 142 | |
148 | 148 | to a list which contains all the elements of the given list, in the same |
149 | 149 | order, which satisfy the predicate. |
150 | 150 | |
151 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
151 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
152 | 152 | | (filter (fun (x) (symbol? x)) (literal (1 two #f 3 () four 5 six)))) |
153 | 153 | = (two four six) |
154 | 154 | |
155 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
155 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
156 | 156 | | (filter (fun (x) (symbol? x)) (literal (1 two #f 3 () four 5 . six)))) |
157 | 157 | ? uncaught exception: (expected-pair . six) |
158 | 158 | |
159 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
159 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
160 | 160 | | (filter (fun (x) x) (literal (#t #t #f banana #t #f)))) |
161 | 161 | ? uncaught exception: (expected-boolean . banana) |
162 | 162 | |
168 | 168 | a list which contains exactly one element, which will be the first |
169 | 169 | element from the list which satisfies the predicate. |
170 | 170 | |
171 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
171 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
172 | 172 | | (find (fun (x) (symbol? x)) ())) |
173 | 173 | = () |
174 | 174 | |
175 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
175 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
176 | 176 | | (find (fun (x) (symbol? x)) (list 1 2 3))) |
177 | 177 | = () |
178 | 178 | |
179 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
179 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
180 | 180 | | (find (fun (x) #t) (list 1 2 3))) |
181 | 181 | = (1) |
182 | 182 | |
183 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
183 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
184 | 184 | | (find (fun (x) (symbol? x)) (literal (1 two #f 3 () four 5 six)))) |
185 | 185 | = (two) |
186 | 186 | |
193 | 193 | second argument to obtain a list. It then evaluates to `#t` if the value |
194 | 194 | is `equal?` to some element of the list, `#f` otherwise. |
195 | 195 | |
196 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
196 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
197 | 197 | | (elem? (literal p) (literal (a p e)))) |
198 | 198 | = #t |
199 | 199 | |
200 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
200 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
201 | 201 | | (elem? (literal p) (literal (a r k)))) |
202 | 202 | = #f |
203 | 203 | |
204 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
204 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
205 | 205 | | (elem? 7 ())) |
206 | 206 | = #f |
207 | 207 | |
208 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
208 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
209 | 209 | | (elem? 7 (list 5 (list 6 7) 8))) |
210 | 210 | = #f |
211 | 211 | |
212 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
212 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
213 | 213 | | (elem? (literal two) (literal (two four . six)))) |
214 | 214 | = #t |
215 | 215 | |
216 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
216 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
217 | 217 | | (elem? (literal eight) (literal (two four . six)))) |
218 | 218 | ? uncaught exception: (expected-pair . six) |
219 | 219 | |
226 | 226 | `append` evaluates both of its arguments to lists. It then |
227 | 227 | evaluates to a list which is the concatenation of these lists. |
228 | 228 | |
229 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
229 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
230 | 230 | | (append (list 1 2 3) (list 4 5 6))) |
231 | 231 | = (1 2 3 4 5 6) |
232 | 232 | |
233 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
233 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
234 | 234 | | (append () ())) |
235 | 235 | = () |
236 | 236 | |
237 | 237 | The second list may be improper, but the first may not be. |
238 | 238 | |
239 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
239 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
240 | 240 | | (append (list 1 2 3) (literal (4 5 . 6)))) |
241 | 241 | = (1 2 3 4 5 . 6) |
242 | 242 | |
243 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
243 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
244 | 244 | | (append (literal (1 2 . 3)) (literal (4 5 6)))) |
245 | 245 | ? uncaught exception: (expected-pair . 3) |
246 | 246 | |
251 | 251 | (the number of pairs, not counting nested pairs and not counting the |
252 | 252 | empty list at the very tail.) |
253 | 253 | |
254 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
254 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
255 | 255 | | (length ())) |
256 | 256 | = 0 |
257 | 257 | |
258 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
258 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
259 | 259 | | (length (list 1 2 #t #f 3))) |
260 | 260 | = 5 |
261 | 261 | |
262 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
262 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
263 | 263 | | (length (literal (1 2 #t #f . 3)))) |
264 | 264 | ? uncaught exception: (expected-pair . 3) |
265 | 265 | |
266 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
266 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
267 | 267 | | (length (literal whatnot))) |
268 | 268 | ? uncaught exception: (expected-pair . whatnot) |
269 | 269 | |
274 | 274 | list at the index given by the natural number. The index is 0-based; |
275 | 275 | 0 refers to the element at the head of the list. |
276 | 276 | |
277 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
277 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
278 | 278 | | (index 0 (literal (the girl from ipanema)))) |
279 | 279 | = the |
280 | 280 | |
281 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
281 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
282 | 282 | | (index 2 (literal (the girl from ipanema)))) |
283 | 283 | = from |
284 | 284 | |
285 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
285 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
286 | 286 | | (bind last (fun (li) (index (subtract (length li) 1) li)) |
287 | 287 | | (last (literal (the girl from ipanema))))) |
288 | 288 | = ipanema |
289 | 289 | |
290 | 290 | Attempting to index beyond the end of the list will raise an exception. |
291 | 291 | |
292 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
292 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
293 | 293 | | (index 7 (literal (the girl from ipanema)))) |
294 | 294 | ? uncaught exception: (expected-pair) |
295 | 295 | |
296 | 296 | `index` expects its first argument to be a number. |
297 | 297 | |
298 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
298 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
299 | 299 | | (index (literal goofy) (list 1 2 3 4 5))) |
300 | 300 | ? uncaught exception: (expected-number . goofy) |
301 | 301 | |
302 | 302 | `index` expects its second argument to be a list. |
303 | 303 | |
304 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
304 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
305 | 305 | | (index 8 (literal whatnot))) |
306 | 306 | ? uncaught exception: (expected-pair . whatnot) |
307 | 307 | |
311 | 311 | second argument to obtain a list. It then evaluates to the longest prefix |
312 | 312 | of the list whose elements all satisfy the predicate. |
313 | 313 | |
314 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
314 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
315 | 315 | | (take-while (fun (x) (symbol? x)) (literal (one two 3 4 five 6 seven)))) |
316 | 316 | = (one two) |
317 | 317 | |
318 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
318 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
319 | 319 | | (take-while (fun (x) (symbol? x)) (literal (1 2 3 4 five six)))) |
320 | 320 | = () |
321 | 321 | |
322 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
322 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
323 | 323 | | (take-while (fun (x) (number? x)) (literal (1 2 3 4 5 6)))) |
324 | 324 | = (1 2 3 4 5 6) |
325 | 325 | |
326 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
326 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
327 | 327 | | (take-while (fun (x) (number? x)) (literal (1 2 3 #f 5 . 6)))) |
328 | 328 | = (1 2 3) |
329 | 329 | |
330 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
330 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
331 | 331 | | (take-while (fun (x) (number? x)) (literal (1 2 3 4 5 . #f)))) |
332 | 332 | ? uncaught exception: (expected-pair . #f) |
333 | 333 | |
334 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
334 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
335 | 335 | | (take-while (fun (x) (symbol? x)) ())) |
336 | 336 | = () |
337 | 337 | |
338 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
338 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
339 | 339 | | (take-while (fun (x) (symbol? x)) #f)) |
340 | 340 | ? uncaught exception: (expected-pair . #f) |
341 | 341 | |
346 | 346 | given list, starting at the first element which does not satisfy the |
347 | 347 | predicate. |
348 | 348 | |
349 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
349 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
350 | 350 | | (drop-while (fun (x) (symbol? x)) (literal (one two 3 4 five 6 seven)))) |
351 | 351 | = (3 4 five 6 seven) |
352 | 352 | |
353 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
353 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
354 | 354 | | (drop-while (fun (x) (symbol? x)) (literal (1 2 3 4 5 6)))) |
355 | 355 | = (1 2 3 4 5 6) |
356 | 356 | |
357 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
357 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
358 | 358 | | (drop-while (fun (x) (number? x)) (literal (1 2 3 4 5 6)))) |
359 | 359 | = () |
360 | 360 | |
361 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
361 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
362 | 362 | | (drop-while (fun (x) (symbol? x)) (literal (one two 3 4 five 6 . seven)))) |
363 | 363 | = (3 4 five 6 . seven) |
364 | 364 | |
365 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
365 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
366 | 366 | | (drop-while (fun (x) (symbol? x)) (literal (one two . three)))) |
367 | 367 | ? uncaught exception: (expected-pair . three) |
368 | 368 | |
369 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
369 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
370 | 370 | | (drop-while (fun (x) (symbol? x)) ())) |
371 | 371 | = () |
372 | 372 | |
373 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
373 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
374 | 374 | | (drop-while (fun (x) (symbol? x)) #f)) |
375 | 375 | ? uncaught exception: (expected-pair . #f) |
376 | 376 | |
380 | 380 | considered to be a desired length, and its second argument to obtain a list. |
381 | 381 | It then evaluates to the prefix of the given list of the desired length. |
382 | 382 | |
383 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
383 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
384 | 384 | | (first 0 (list 1 2 3 4 5))) |
385 | 385 | = () |
386 | 386 | |
387 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
387 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
388 | 388 | | (first 3 (list 1 2 3 4 5))) |
389 | 389 | = (1 2 3) |
390 | 390 | |
391 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
391 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
392 | 392 | | (first 6 (list 1 2 3 4 5))) |
393 | 393 | ? uncaught exception: (expected-pair) |
394 | 394 | |
395 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
395 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
396 | 396 | | (first 6 (list 1 2 3 4 5 . 6))) |
397 | 397 | ? uncaught exception: (expected-pair . 6) |
398 | 398 | |
399 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
399 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
400 | 400 | | (first 1 (literal foo))) |
401 | 401 | ? uncaught exception: (expected-pair . foo) |
402 | 402 | |
403 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
403 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
404 | 404 | | (first 0 (literal foo))) |
405 | 405 | = () |
406 | 406 | |
411 | 411 | list. It then evaluates to the suffix of the given list starting at the |
412 | 412 | desired position. The position 0 indicates the beginning of the list. |
413 | 413 | |
414 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
414 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
415 | 415 | | (rest 0 (list 1 2 3 4 5))) |
416 | 416 | = (1 2 3 4 5) |
417 | 417 | |
418 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
418 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
419 | 419 | | (rest 3 (list 1 2 3 4 5))) |
420 | 420 | = (4 5) |
421 | 421 | |
422 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
422 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
423 | 423 | | (rest 5 (list 1 2 3 4 5))) |
424 | 424 | = () |
425 | 425 | |
426 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
426 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
427 | 427 | | (rest 6 (list 1 2 3 4 5))) |
428 | 428 | ? uncaught exception: (expected-pair) |
429 | 429 | |
430 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
430 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
431 | 431 | | (rest 6 (list 1 2 3 4 5 . 6))) |
432 | 432 | ? uncaught exception: (expected-pair . 6) |
433 | 433 | |
434 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
434 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
435 | 435 | | (rest 1 (literal foo))) |
436 | 436 | ? uncaught exception: (expected-pair . foo) |
437 | 437 | |
438 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
438 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
439 | 439 | | (rest 0 (literal foo))) |
440 | 440 | = foo |
441 | 441 | |
446 | 446 | list. It then evaluates to the suffix of the given list of the desired |
447 | 447 | length. |
448 | 448 | |
449 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
449 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
450 | 450 | | (last 0 (list 1 2 3 4 5))) |
451 | 451 | = () |
452 | 452 | |
453 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
453 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
454 | 454 | | (head (last 1 (list 1 2 3 4 5)))) |
455 | 455 | = 5 |
456 | 456 | |
457 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
457 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
458 | 458 | | (last 3 (list 1 2 3 4 5))) |
459 | 459 | = (3 4 5) |
460 | 460 | |
461 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
461 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
462 | 462 | | (last 6 (list 1 2 3 4 5))) |
463 | 463 | ? uncaught exception: (expected-pair) |
464 | 464 | |
465 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
465 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
466 | 466 | | (last 6 (list 1 2 3 4 5 . 6))) |
467 | 467 | ? uncaught exception: (expected-pair . 6) |
468 | 468 | |
469 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
469 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
470 | 470 | | (last 1 (literal foo))) |
471 | 471 | ? uncaught exception: (expected-pair . foo) |
472 | 472 | |
473 | 473 | Unlike `first`, `last` does care if it's not a list, even when the count |
474 | 474 | is zero. |
475 | 475 | |
476 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
476 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
477 | 477 | | (last 0 (literal foo))) |
478 | 478 | ? uncaught exception: (expected-pair . foo) |
479 | 479 | |
485 | 485 | or the head of A is `equal?` to the head of B and the tail of A is a |
486 | 486 | prefix of the tail of B. |
487 | 487 | |
488 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
488 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
489 | 489 | | (prefix? (list 1 2 3) (list 1 2 3 4 5 6))) |
490 | 490 | = #t |
491 | 491 | |
492 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
492 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
493 | 493 | | (prefix? (list 1 2 5) (list 1 2 3 4 5 6))) |
494 | 494 | = #f |
495 | 495 | |
496 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
496 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
497 | 497 | | (prefix? () (list 1 2 3 4 5 6))) |
498 | 498 | = #t |
499 | 499 | |
500 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
500 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
501 | 501 | | (prefix? () (literal schpritz))) |
502 | 502 | = #t |
503 | 503 | |
504 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
504 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
505 | 505 | | (prefix? (list 1 2 3) (list 1 2 3))) |
506 | 506 | = #t |
507 | 507 | |
508 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
508 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
509 | 509 | | (prefix? (list 1 2 3 4) (list 1 2 3))) |
510 | 510 | = #f |
511 | 511 | |
512 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
512 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
513 | 513 | | (prefix? (literal (1 2 3)) (literal (1 2 3 4 5 . 6)))) |
514 | 514 | = #t |
515 | 515 | |
516 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
516 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
517 | 517 | | (prefix? (literal (1 2 3 4 8)) (literal (1 2 3 4 5 . 6)))) |
518 | 518 | = #f |
519 | 519 | |
520 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
520 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
521 | 521 | | (prefix? (literal (1 2 . 3)) (literal (1 2 . 3)))) |
522 | 522 | ? uncaught exception: (expected-pair . 3) |
523 | 523 | |
524 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
524 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
525 | 525 | | (prefix? (literal (1 2 4 8)) (literal (1 2 . 3)))) |
526 | 526 | ? uncaught exception: (expected-pair . 3) |
527 | 527 | |
535 | 535 | is applied recursively to any elements in sublists which are themselves |
536 | 536 | sublists. |
537 | 537 | |
538 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
538 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
539 | 539 | | (flatten ())) |
540 | 540 | = () |
541 | 541 | |
542 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
542 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
543 | 543 | | (flatten (list 1 2 3))) |
544 | 544 | = (1 2 3) |
545 | 545 | |
546 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
546 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
547 | 547 | | (flatten (list 1 (list 2 3 4) 5))) |
548 | 548 | = (1 2 3 4 5) |
549 | 549 | |
550 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
550 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
551 | 551 | | (flatten (list 1 (list 2 3 (list 4 4 4)) 5))) |
552 | 552 | = (1 2 3 4 4 4 5) |
553 | 553 | |
554 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
554 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
555 | 555 | | (flatten (list 1 () 5))) |
556 | 556 | = (1 5) |
557 | 557 | |
558 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
558 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
559 | 559 | | (flatten (list 1 (pair 2 3) 4))) |
560 | 560 | = (1 (2 . 3) 4) |
561 | 561 | |
562 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
562 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
563 | 563 | | (flatten (list 1 (literal (2 3 . 4)) 5))) |
564 | 564 | = (1 (2 3 . 4) 5) |
565 | 565 | |
566 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
566 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
567 | 567 | | (flatten (literal (1 2 . 3)))) |
568 | 568 | ? uncaught exception: (expected-pair . 3) |
569 | 569 | |
570 | 570 | ### `lookup` ### |
571 | 571 | |
572 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
572 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
573 | 573 | | (lookup (literal b) (literal ((a . 1) (b . 2) (c . 3))))) |
574 | 574 | = (2) |
575 | 575 | |
576 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
576 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
577 | 577 | | (lookup (literal a) (literal ((a . 1) (a . 2) (a . 3))))) |
578 | 578 | = (1) |
579 | 579 | |
580 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
580 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
581 | 581 | | (lookup (literal r) (literal ((a . 1) (b . 2) (c . 3))))) |
582 | 582 | = () |
583 | 583 | |
584 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
584 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
585 | 585 | | (lookup (literal q) ())) |
586 | 586 | = () |
587 | 587 | |
588 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
588 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
589 | 589 | | (lookup (literal q) 55)) |
590 | 590 | ? uncaught exception: (expected-pair . 55) |
591 | 591 | |
592 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
592 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
593 | 593 | | (lookup (literal q) (literal ((a . 7) 99 (q . 4))))) |
594 | 594 | ? uncaught exception: (expected-pair . 99) |
595 | 595 | |
596 | 596 | ### `extend` ### |
597 | 597 | |
598 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
598 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
599 | 599 | | (extend (literal b) 6 (literal ((a . 1) (b .2) (c .3))))) |
600 | 600 | = ((b . 6) (a . 1) (b . 2) (c . 3)) |
601 | 601 | |
602 | 602 | The following should be true for any identifier i and alist x. |
603 | 603 | |
604 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
604 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
605 | 605 | | (let ((i (literal a)) |
606 | 606 | | (x (literal ((f . 5) (g . 7))))) |
607 | 607 | | (lookup i (extend i 1 x)))) |
608 | 608 | = (1) |
609 | 609 | |
610 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
610 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
611 | 611 | | (extend (literal b) 6 81)) |
612 | 612 | = ((b . 6) . 81) |
613 | 613 | |
614 | 614 | ### `delete` ### |
615 | 615 | |
616 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
616 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
617 | 617 | | (delete (literal b) (literal ((a . 1) (b . 2) (c . 3))))) |
618 | 618 | = ((a . 1) (c . 3)) |
619 | 619 | |
620 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
620 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
621 | 621 | | (delete (literal b) (literal ((a . 1) (b . 2) (c . 3) (b . 4))))) |
622 | 622 | = ((a . 1) (c . 3)) |
623 | 623 | |
624 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
624 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
625 | 625 | | (delete (literal r) (literal ((a . 1) (b . 2) (c . 3))))) |
626 | 626 | = ((a . 1) (b . 2) (c . 3)) |
627 | 627 | |
628 | 628 | The following should be true for any identifier i and alist x. |
629 | 629 | |
630 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
630 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
631 | 631 | | (let ((i (literal a)) |
632 | 632 | | (x (literal ((a . 5) (b . 7))))) |
633 | 633 | | (lookup i (delete i x)))) |
634 | 634 | = () |
635 | 635 | |
636 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
636 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
637 | 637 | | (delete (literal q) 55)) |
638 | 638 | ? uncaught exception: (expected-pair . 55) |
639 | 639 | |
640 | | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
640 | | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
641 | 641 | | (delete (literal q) (literal ((a . 7) 99 (q . 4))))) |
642 | 642 | ? uncaught exception: (expected-pair . 99) |
14 | 14 | is not loaded twice. |
15 | 15 | |
16 | 16 | | ----- module a 0.1 |
17 | | (robin (0 . 1) (small (0 . 1) random (0 . 1)) | |
17 | | (robin (0 1) ((small (0 1) *) (random (0 1) *)) | |
18 | 18 | | (pair (pair (literal random-a) random) ())) |
19 | 19 | | ----- module b 0.1 |
20 | | (robin (0 . 1) (small (0 . 1) random (0 . 1)) | |
20 | | (robin (0 1) ((small (0 1) *) (random (0 1) *)) | |
21 | 21 | | (pair (pair (literal random-b) random) ())) |
22 | 22 | | ----- main |
23 | | (robin (0 . 1) (core (0 . 1) a (0 . 1) b (0 . 1)) | |
23 | | (robin (0 1) ((core (0 1) *) (a (0 1) *) (b (0 1) *)) | |
24 | 24 | | (equal? random-a random-b)) |
25 | 25 | = #t |
26 | 26 | |
28 | 28 | loop. |
29 | 29 | |
30 | 30 | | ----- module a 0.1 |
31 | | (robin (0 . 1) (small (0 . 1) b (0 . 1)) | |
31 | | (robin (0 1) ((small (0 1) *) (b (0 1) *)) | |
32 | 32 | | (pair (pair (literal literal-a) literal-b) ())) |
33 | 33 | | ----- module b 0.1 |
34 | | (robin (0 . 1) (small (0 . 1) a (0 . 1)) | |
34 | | (robin (0 1) ((small (0 1) *) (a (0 1) *)) | |
35 | 35 | | (pair (pair (literal literal-b) literal-a) ())) |
36 | 36 | | ----- main |
37 | | (robin (0 . 1) (core (0 . 1) a (0 . 1)) | |
37 | | (robin (0 1) ((core (0 1) *) (a (0 1) *)) | |
38 | 38 | | (equal? literal-a literal-b)) |
39 | 39 | ? robin: circular reference in module a |
40 | 40 | |
41 | -> Tests for shell command "bin/robin %(test-file)" | |
41 | -> Functionality "Interpret Robin Program" is implemented by | |
42 | -> shell command "bin/robin %(test-file)" | |
43 | ||
44 | -> Tests for functionality "Interpret Robin Program" | |
42 | 45 | |
43 | 46 | `and` is short-circuiting. |
44 | 47 | |
45 | | (robin (0 . 1) (small (0 . 1) boolean (0 . 1) concurrency (0 . 1) crude-io (0 . 1)) | |
48 | | (robin (0 1) ((small (0 1) *) (boolean (0 1) *) (concurrency (0 1) *) (crude-io (0 1) *)) | |
46 | 49 | | (let ((true |
47 | 50 | | (fun () (call! crude-output write (literal t) reply #t))) |
48 | 51 | | (false |
54 | 57 | |
55 | 58 | `or` is short-circuiting. |
56 | 59 | |
57 | | (robin (0 . 1) (small (0 . 1) boolean (0 . 1) concurrency (0 . 1) crude-io (0 . 1)) | |
60 | | (robin (0 1) ((small (0 1) *) (boolean (0 1) *) (concurrency (0 1) *) (crude-io (0 1) *)) | |
58 | 61 | | (let ((true |
59 | 62 | | (fun () (call! crude-output write (literal t) reply #t))) |
60 | 63 | | (false |
32 | 32 | but marked with `pure` in the metadata (except `eval` where this is far |
33 | 33 | from a guarantee.) |
34 | 34 | |
35 | | (robin (0 . 1) (pure (0 . 1)) | |
35 | | (robin (0 1) ((pure (0 1) *)) | |
36 | 36 | | (has? (literal pure) head)) |
37 | 37 | = #t |
38 | 38 | |
39 | | (robin (0 . 1) (pure (0 . 1)) | |
39 | | (robin (0 1) ((pure (0 1) *)) | |
40 | 40 | | (has? (literal pure) tail)) |
41 | 41 | = #t |
42 | 42 | |
43 | | (robin (0 . 1) (pure (0 . 1)) | |
43 | | (robin (0 1) ((pure (0 1) *)) | |
44 | 44 | | (has? (literal pure) pair)) |
45 | 45 | = #t |
46 | 46 | |
47 | | (robin (0 . 1) (pure (0 . 1)) | |
47 | | (robin (0 1) ((pure (0 1) *)) | |
48 | 48 | | (has? (literal pure) if)) |
49 | 49 | = #t |
50 | 50 | |
51 | | (robin (0 . 1) (pure (0 . 1)) | |
51 | | (robin (0 1) ((pure (0 1) *)) | |
52 | 52 | | (has? (literal pure) macro)) |
53 | 53 | = #t |
54 | 54 | |
55 | | (robin (0 . 1) (pure (0 . 1)) | |
55 | | (robin (0 1) ((pure (0 1) *)) | |
56 | 56 | | (has? (literal pure) fun)) |
57 | 57 | = #t |
58 | 58 | |
79 | 79 | of symbols which are the formal parameters of the function. The third |
80 | 80 | argument is a literal term which is the body of the function. |
81 | 81 | |
82 | | (robin (0 . 1) (pure (0 . 1)) | |
82 | | (robin (0 1) ((pure (0 1) *)) | |
83 | 83 | | (pure-expr? (env) () (literal 4))) |
84 | 84 | = #t |
85 | 85 | |
86 | | (robin (0 . 1) (pure (0 . 1)) | |
86 | | (robin (0 1) ((pure (0 1) *)) | |
87 | 87 | | (pure-expr? (env) () (literal (subtract 4 5)))) |
88 | 88 | = #t |
89 | 89 | |
90 | | (robin (0 . 1) (pure (0 . 1)) | |
90 | | (robin (0 1) ((pure (0 1) *)) | |
91 | 91 | | (pure-expr? (env) (literal (a b)) (literal (subtract a b)))) |
92 | 92 | = #t |
93 | 93 | |
94 | | (robin (0 . 1) (pure (0 . 1) concurrency (0 . 1)) | |
94 | | (robin (0 1) ((pure (0 1) *) (concurrency (0 1) *)) | |
95 | 95 | | (pure-expr? (env) (literal (a b)) (literal (send! (myself) 3)))) |
96 | 96 | = #f |
97 | 97 | |
98 | 98 | An otherwise pure function which simply binds something that it does not use |
99 | 99 | is still pure. |
100 | 100 | |
101 | | (robin (0 . 1) (pure (0 . 1)) | |
101 | | (robin (0 1) ((pure (0 1) *)) | |
102 | 102 | | (pure-expr? (env) (literal (x)) (literal |
103 | 103 | | (bind y 23 x)))) |
104 | 104 | = #t |
106 | 106 | An otherwise pure function which binds some pure values to names is still |
107 | 107 | pure. |
108 | 108 | |
109 | | (robin (0 . 1) (pure (0 . 1)) | |
109 | | (robin (0 1) ((pure (0 1) *)) | |
110 | 110 | | (pure-expr? (env) (literal (x)) (literal |
111 | 111 | | (bind y (subtract x 23) (bind r 5 (subtract y r)))))) |
112 | 112 | = #t |
113 | 113 | |
114 | 114 | A function which evaluates to a pure built-in function is pure. |
115 | 115 | |
116 | | (robin (0 . 1) (pure (0 . 1)) | |
116 | | (robin (0 1) ((pure (0 1) *)) | |
117 | 117 | | (pure-expr? (env) (literal (foo)) (literal head))) |
118 | 118 | = #t |
119 | 119 | |
120 | 120 | A function which evaluates to a pure function is pure. |
121 | 121 | |
122 | | (robin (0 . 1) (pure (0 . 1)) | |
122 | | (robin (0 1) ((pure (0 1) *)) | |
123 | 123 | | (pure-expr? (env) (literal (foo)) (literal (fun (x) x)))) |
124 | 124 | = #t |
125 | 125 | |
127 | 127 | the impure function is determined entirely by the parameters to the pure |
128 | 128 | function. |
129 | 129 | |
130 | | (robin (0 . 1) (pure (0 . 1) concurrency (0 . 1)) | |
130 | | (robin (0 1) ((pure (0 1) *) (concurrency (0 1) *)) | |
131 | 131 | | (pure-expr? (env) () (literal |
132 | 132 | | (fun (x) (send! x 3))))) |
133 | 133 | = #t |
134 | 134 | |
135 | 135 | Even if it uses a closed-over identifier. |
136 | 136 | |
137 | | (robin (0 . 1) (pure (0 . 1) concurrency (0 . 1)) | |
137 | | (robin (0 1) ((pure (0 1) *) (concurrency (0 1) *)) | |
138 | 138 | | (pure-expr? (env) (literal (pid)) (literal |
139 | 139 | | (fun (x) (send! pid x))))) |
140 | 140 | = #t |
141 | 141 | |
142 | 142 | Even if it evaluates to multiple functions. |
143 | 143 | |
144 | | (robin (0 . 1) (pure (0 . 1) concurrency (0 . 1)) | |
144 | | (robin (0 1) ((pure (0 1) *) (concurrency (0 1) *)) | |
145 | 145 | | (pure-expr? (env) (literal (pid)) (literal |
146 | 146 | | (pair (fun () pid) |
147 | 147 | | (fun (x) (send! pid x)))))) |
150 | 150 | An otherwise pure function which calls a pure function that it defines |
151 | 151 | within itself is pure. |
152 | 152 | |
153 | | (robin (0 . 1) (pure (0 . 1)) | |
153 | | (robin (0 1) ((pure (0 1) *)) | |
154 | 154 | | (pure-expr? (env) (literal (x)) (literal |
155 | 155 | | ((fun (y) y) 123)))) |
156 | 156 | = #t |
157 | 157 | |
158 | 158 | (Unless of course, one of its actual arguments is not.) |
159 | 159 | |
160 | | (robin (0 . 1) (pure (0 . 1)) | |
160 | | (robin (0 1) ((pure (0 1) *)) | |
161 | 161 | | (pure-expr? (env) (literal (x)) (literal |
162 | 162 | | ((fun (y) y) (send! x 14))))) |
163 | 163 | = #f |
164 | 164 | |
165 | 165 | Even if it uses closed-over identifiers. |
166 | 166 | |
167 | | (robin (0 . 1) (pure (0 . 1)) | |
167 | | (robin (0 1) ((pure (0 1) *)) | |
168 | 168 | | (pure-expr? (env) (literal (x)) (literal |
169 | 169 | | ((fun (y) x) 123)))) |
170 | 170 | = #t |
171 | 171 | |
172 | 172 | Even if it was bound to a name first. |
173 | 173 | |
174 | | (robin (0 . 1) (pure (0 . 1)) | |
174 | | (robin (0 1) ((pure (0 1) *)) | |
175 | 175 | | (pure-expr? (env) (literal (x)) (literal |
176 | 176 | | (bind y (fun (z) z) |
177 | 177 | | (y 123))))) |
179 | 179 | |
180 | 180 | Even if it was bound to a name first, and uses closed-over identifiers. |
181 | 181 | |
182 | | (robin (0 . 1) (pure (0 . 1)) | |
182 | | (robin (0 1) ((pure (0 1) *)) | |
183 | 183 | | (pure-expr? (env) (literal (x)) (literal |
184 | 184 | | (bind y (fun (z) (pair x z)) |
185 | 185 | | (y 123))))) |
188 | 188 | An otherwise pure function which calls an impure function that it defines |
189 | 189 | within itself is not pure. |
190 | 190 | |
191 | | (robin (0 . 1) (pure (0 . 1) concurrency (0 . 1)) | |
191 | | (robin (0 1) ((pure (0 1) *) (concurrency (0 1) *)) | |
192 | 192 | | (pure-expr? (env) (literal (pid)) (literal |
193 | 193 | | ((fun (j) (send! j 3)) pid)))) |
194 | 194 | = #f |
195 | 195 | |
196 | 196 | Even if that impure function was bound to a name first. |
197 | 197 | |
198 | | (robin (0 . 1) (pure (0 . 1) concurrency (0 . 1)) | |
198 | | (robin (0 1) ((pure (0 1) *) (concurrency (0 1) *)) | |
199 | 199 | | (pure-expr? (env) (literal (pid)) (literal |
200 | 200 | | (bind zap! (fun (j) (send! j 3)) |
201 | 201 | | (zap! pid))))) |
204 | 204 | If we bind a name to an impure expression, the function is not pure, even |
205 | 205 | if it doesn't use the name. |
206 | 206 | |
207 | | (robin (0 . 1) (pure (0 . 1) concurrency (0 . 1)) | |
207 | | (robin (0 1) ((pure (0 1) *) (concurrency (0 1) *)) | |
208 | 208 | | (pure-expr? (env) (literal (pid)) (literal |
209 | 209 | | (bind n (send! pid 3) pid)))) |
210 | 210 | = #f |
212 | 212 | A function which applies one of its arguments is not pure, because its |
213 | 213 | argument might not be pure. |
214 | 214 | |
215 | | (robin (0 . 1) (pure (0 . 1)) | |
215 | | (robin (0 1) ((pure (0 1) *)) | |
216 | 216 | | (pure-expr? (env) (literal (x)) (literal |
217 | 217 | | (x 123)))) |
218 | 218 | = #f |
221 | 221 | |
222 | 222 | TBW |
223 | 223 | |
224 | | (robin (0 . 1) (pure (0 . 1)) | |
224 | | (robin (0 1) ((pure (0 1) *)) | |
225 | 225 | | (pure-fun-defn? (env) (literal |
226 | 226 | | (fun (a) a)))) |
227 | 227 | = #t |
228 | 228 | |
229 | 229 | We don't do macros yet. |
230 | 230 | |
231 | | (robin (0 . 1) (pure (0 . 1)) | |
231 | | (robin (0 1) ((pure (0 1) *)) | |
232 | 232 | | (pure-fun-defn? (env) (literal |
233 | 233 | | (macro (self args env) args)))) |
234 | 234 | = #f |
235 | 235 | |
236 | | (robin (0 . 1) (pure (0 . 1)) | |
236 | | (robin (0 1) ((pure (0 1) *)) | |
237 | 237 | | (pure-fun-defn? (env) (literal |
238 | 238 | | head))) |
239 | 239 | = #t |
240 | 240 | |
241 | | (robin (0 . 1) (pure (0 . 1) concurrency (0 . 1)) | |
241 | | (robin (0 1) ((pure (0 1) *) (concurrency (0 1) *)) | |
242 | 242 | | (pure-fun-defn? (env) (literal |
243 | 243 | | (fun (a) (send! a a))))) |
244 | 244 | = #f |
245 | 245 | |
246 | | (robin (0 . 1) (pure (0 . 1) concurrency (0 . 1)) | |
246 | | (robin (0 1) ((pure (0 1) *) (concurrency (0 1) *)) | |
247 | 247 | | (pure-fun-defn? (env) (literal |
248 | 248 | | send!))) |
249 | 249 | = #f |
251 | 251 | This is actually pure, but too complex for us to analyze right now, |
252 | 252 | so we pessimistically say no. |
253 | 253 | |
254 | | (robin (0 . 1) (pure (0 . 1)) | |
254 | | (robin (0 1) ((pure (0 1) *)) | |
255 | 255 | | (pure-fun-defn? (env) (literal |
256 | 256 | | ((head (pair fun ())) (a) a)))) |
257 | 257 | = #f |
12 | 12 | |
13 | 13 | -> Tests for functionality "Interpret Robin Program" |
14 | 14 | |
15 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1) arith (0 . 1) random (0 . 1)) | |
15 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *) (arith (0 1) *) (random (0 1) *)) | |
16 | 16 | | (call! random range (pair 1 (pair 6 ())) value |
17 | 17 | | (< value 7))) |
18 | 18 | = #t |
19 | 19 | |
20 | | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1) arith (0 . 1) random (0 . 1)) | |
20 | | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *) (arith (0 1) *) (random (0 1) *)) | |
21 | 21 | | (call! random range (pair 1 (pair 6 ())) value |
22 | 22 | | (>= value 1))) |
23 | 23 | = #t |
36 | 36 | which evaluates to the literal content of its sole argument, which can be |
37 | 37 | any S-expression. |
38 | 38 | |
39 | | (robin (0 . 1) (small (0 . 1)) | |
39 | | (robin (0 1) ((small (0 1) *)) | |
40 | 40 | | (literal symbol)) |
41 | 41 | = symbol |
42 | 42 | |
43 | | (robin (0 . 1) (small (0 . 1)) | |
43 | | (robin (0 1) ((small (0 1) *)) | |
44 | 44 | | (literal (a . pair))) |
45 | 45 | = (a . pair) |
46 | 46 | |
47 | | (robin (0 . 1) (small (0 . 1)) | |
47 | | (robin (0 1) ((small (0 1) *)) | |
48 | 48 | | (literal (hello world))) |
49 | 49 | = (hello world) |
50 | 50 | |
54 | 54 | |
55 | 55 | You can define functions with `fun`. They can be anonymous. |
56 | 56 | |
57 | | (robin (0 . 1) (small (0 . 1)) | |
57 | | (robin (0 1) ((small (0 1) *)) | |
58 | 58 | | ((fun (a) a) (literal whee))) |
59 | 59 | = whee |
60 | 60 | |
62 | 62 | function is defined will still be in force when the function is applied, |
63 | 63 | even if they are no longer lexically in scope. |
64 | 64 | |
65 | | (robin (0 . 1) (small (0 . 1)) | |
65 | | (robin (0 1) ((small (0 1) *)) | |
66 | 66 | | ((let |
67 | 67 | | ((a (literal (hi))) |
68 | 68 | | (f (fun (x) (pair x a)))) |
71 | 71 | |
72 | 72 | Functions can take functions. |
73 | 73 | |
74 | | (robin (0 . 1) (small (0 . 1)) | |
74 | | (robin (0 1) ((small (0 1) *)) | |
75 | 75 | | (let |
76 | 76 | | ((apply (fun (x) (x (literal a))))) |
77 | 77 | | (apply (fun (r) (pair r (literal ())))))) |
79 | 79 | |
80 | 80 | Functions can return functions. |
81 | 81 | |
82 | | (robin (0 . 1) (small (0 . 1)) | |
82 | | (robin (0 1) ((small (0 1) *)) | |
83 | 83 | | (let |
84 | 84 | | ((mk (fun (x) (fun (y) (pair y x)))) |
85 | 85 | | (mk2 (mk (literal (vindaloo))))) |
88 | 88 | |
89 | 89 | Arguments to functions shadow any other bindings in effect. |
90 | 90 | |
91 | | (robin (0 . 1) (small (0 . 1)) | |
91 | | (robin (0 1) ((small (0 1) *)) | |
92 | 92 | | (let |
93 | 93 | | ((a (literal a)) |
94 | 94 | | (b (fun (a) (pair a a)))) |
97 | 97 | |
98 | 98 | A function may have no arguments at all. |
99 | 99 | |
100 | | (robin (0 . 1) (small (0 . 1)) | |
100 | | (robin (0 1) ((small (0 1) *)) | |
101 | 101 | | ((fun () 7))) |
102 | 102 | = 7 |
103 | 103 | |
109 | 109 | expression, and makes that binding available in another expression which |
110 | 110 | it evaluates. |
111 | 111 | |
112 | | (robin (0 . 1) (small (0 . 1)) | |
112 | | (robin (0 1) ((small (0 1) *)) | |
113 | 113 | | (bind x (literal hello) |
114 | 114 | | (pair x x))) |
115 | 115 | = (hello . hello) |
116 | 116 | |
117 | | (robin (0 . 1) (small (0 . 1)) | |
117 | | (robin (0 1) ((small (0 1) *)) | |
118 | 118 | | (bind dup (fun (x) (pair x x)) |
119 | 119 | | (dup (literal g)))) |
120 | 120 | = (g . g) |
121 | 121 | |
122 | | (robin (0 . 1) (small (0 . 1)) | |
122 | | (robin (0 1) ((small (0 1) *)) | |
123 | 123 | | (bind dup (fun (x) (pair x x)) |
124 | 124 | | (dup (dup (literal g))))) |
125 | 125 | = ((g . g) g . g) |
126 | 126 | |
127 | | (robin (0 . 1) (small (0 . 1)) | |
127 | | (robin (0 1) ((small (0 1) *)) | |
128 | 128 | | (bind smoosh (fun (x y) (pair y x)) |
129 | 129 | | (smoosh #t #f))) |
130 | 130 | = (#f . #t) |
131 | 131 | |
132 | | (robin (0 . 1) (small (0 . 1)) | |
132 | | (robin (0 1) ((small (0 1) *)) | |
133 | 133 | | (bind find (fun (self alist key) |
134 | 134 | | (if (equal? alist (literal ())) (literal ()) |
135 | 135 | | (if (equal? key (head (head alist))) |
147 | 147 | |
148 | 148 | An identifier can be bound to a symbol. |
149 | 149 | |
150 | | (robin (0 . 1) (small (0 . 1)) | |
150 | | (robin (0 1) ((small (0 1) *)) | |
151 | 151 | | (let ((a (literal hello))) a)) |
152 | 152 | = hello |
153 | 153 | |
154 | 154 | `let` can appear in the binding expression in a `let`. |
155 | 155 | |
156 | | (robin (0 . 1) (small (0 . 1)) | |
156 | | (robin (0 1) ((small (0 1) *)) | |
157 | 157 | | (let ((a (let ((b (literal c))) b))) a)) |
158 | 158 | = c |
159 | 159 | |
160 | 160 | `let` can bind a symbol to a function value. |
161 | 161 | |
162 | | (robin (0 . 1) (small (0 . 1)) | |
162 | | (robin (0 1) ((small (0 1) *)) | |
163 | 163 | | (let ((a (fun (x y) (pair x y)))) |
164 | 164 | | (a (literal foo) (literal ())))) |
165 | 165 | = (foo) |
167 | 167 | Bindings established in a `let` remain in effect when evaluating |
168 | 168 | the arguments things in the body of the `let`. |
169 | 169 | |
170 | | (robin (0 . 1) (small (0 . 1)) | |
170 | | (robin (0 1) ((small (0 1) *)) | |
171 | 171 | | (let ((dup (fun (x) (pair x x)))) |
172 | 172 | | (dup (dup (literal g))))) |
173 | 173 | = ((g . g) g . g) |
175 | 175 | Bindings established in a binding in a `let` can be seen in |
176 | 176 | subsequent bindings in the same `let`. |
177 | 177 | |
178 | | (robin (0 . 1) (small (0 . 1)) | |
178 | | (robin (0 1) ((small (0 1) *)) | |
179 | 179 | | (let ((a (literal hello)) (b (pair a (literal ())))) b)) |
180 | 180 | = (hello) |
181 | 181 | |
182 | 182 | Shadowing happens. |
183 | 183 | |
184 | | (robin (0 . 1) (small (0 . 1)) | |
184 | | (robin (0 1) ((small (0 1) *)) | |
185 | 185 | | (let ((a (literal hello))) (let ((a (literal goodbye))) a))) |
186 | 186 | = goodbye |
187 | 187 | |
188 | 188 | `let` can have an empty list of bindings. |
189 | 189 | |
190 | | (robin (0 . 1) (small (0 . 1)) | |
190 | | (robin (0 1) ((small (0 1) *)) | |
191 | 191 | | (let () (literal hi))) |
192 | 192 | = hi |
193 | 193 | |
203 | 203 | condition in the final test must be the literal symbol `else`; the |
204 | 204 | corresponding expression will be evaluated if all other tests failed. |
205 | 205 | |
206 | | (robin (0 . 1) (small (0 . 1)) | |
206 | | (robin (0 1) ((small (0 1) *)) | |
207 | 207 | | (choose (#t (literal hi)) (else (literal lo)))) |
208 | 208 | = hi |
209 | 209 | |
210 | | (robin (0 . 1) (small (0 . 1)) | |
210 | | (robin (0 1) ((small (0 1) *)) | |
211 | 211 | | (choose (#f (literal hi)) (#t (literal med)) (else (literal lo)))) |
212 | 212 | = med |
213 | 213 | |
214 | | (robin (0 . 1) (small (0 . 1)) | |
214 | | (robin (0 1) ((small (0 1) *)) | |
215 | 215 | | (choose (#f (literal hi)) (#f (literal med)) (else (literal lo)))) |
216 | 216 | = lo |
217 | 217 | |
218 | 218 | `choose` can have zero tests before the `else`. |
219 | 219 | |
220 | | (robin (0 . 1) (small (0 . 1)) | |
220 | | (robin (0 1) ((small (0 1) *)) | |
221 | 221 | | (choose (else (literal woo)))) |
222 | 222 | = woo |
223 | 223 | |
228 | 228 | `env` evaluates to all the bindings in effect at the point of execution |
229 | 229 | where this form is encountered, as an alist. |
230 | 230 | |
231 | | (robin (0 . 1) (small (0 . 1)) | |
231 | | (robin (0 1) ((small (0 1) *)) | |
232 | 232 | | (bind find (fun (self alist key) |
233 | 233 | | (if (equal? alist (literal ())) (literal ()) |
234 | 234 | | (if (equal? key (head (head alist))) |
17 | 17 | value (even those deeply nested within subpairs) have been replaced with the |
18 | 18 | second value. |
19 | 19 | |
20 | | (robin (0 . 1) (small (0 . 1) term (0 . 1)) | |
20 | | (robin (0 1) ((small (0 1) *) (term (0 1) *)) | |
21 | 21 | | (subst 4 5 4)) |
22 | 22 | = 5 |
23 | 23 | |
24 | | (robin (0 . 1) (small (0 . 1) term (0 . 1)) | |
24 | | (robin (0 1) ((small (0 1) *) (term (0 1) *)) | |
25 | 25 | | (subst 4 5 (literal (1 2 3 4 5)))) |
26 | 26 | = (1 2 3 5 5) |
27 | 27 | |
28 | | (robin (0 . 1) (small (0 . 1) term (0 . 1)) | |
28 | | (robin (0 1) ((small (0 1) *) (term (0 1) *)) | |
29 | 29 | | (subst 4 5 (literal (one two three four five)))) |
30 | 30 | = (one two three four five) |
31 | 31 | |
32 | | (robin (0 . 1) (small (0 . 1) term (0 . 1)) | |
32 | | (robin (0 1) ((small (0 1) *) (term (0 1) *)) | |
33 | 33 | | (subst 4 5 (literal (4 1 4 1 4)))) |
34 | 34 | = (5 1 5 1 5) |
35 | 35 | |
36 | | (robin (0 . 1) (small (0 . 1) term (0 . 1)) | |
36 | | (robin (0 1) ((small (0 1) *) (term (0 1) *)) | |
37 | 37 | | (subst 4 5 (literal (1 4 (1 4 (4 1) 4) 4)))) |
38 | 38 | = (1 5 (1 5 (5 1) 5) 5) |
39 | 39 | |
40 | | (robin (0 . 1) (small (0 . 1) term (0 . 1)) | |
40 | | (robin (0 1) ((small (0 1) *) (term (0 1) *)) | |
41 | 41 | | (subst 4 () (literal (1 2 3 4)))) |
42 | 42 | = (1 2 3 ()) |
43 | 43 | |
44 | | (robin (0 . 1) (small (0 . 1) term (0 . 1)) | |
44 | | (robin (0 1) ((small (0 1) *) (term (0 1) *)) | |
45 | 45 | | (subst 4 () (literal (1 2 3 . 4)))) |
46 | 46 | = (1 2 3) |
47 | 47 | |
48 | | (robin (0 . 1) (small (0 . 1) term (0 . 1)) | |
48 | | (robin (0 1) ((small (0 1) *) (term (0 1) *)) | |
49 | 49 | | (subst (literal (turkey and cheese)) (literal (pastrami and rye)) |
50 | 50 | | (pair (literal (turkey and bacon)) (literal (turkey and cheese))))) |
51 | 51 | = ((turkey and bacon) pastrami and rye) |
52 | 52 | |
53 | 53 | ### `subst-many` ### |
54 | 54 | |
55 | | (robin (0 . 1) (small (0 . 1) term (0 . 1)) | |
55 | | (robin (0 1) ((small (0 1) *) (term (0 1) *)) | |
56 | 56 | | (subst-many (literal ((p . 100) (q . 200))) |
57 | 57 | | (literal (a d (r p q) q (p (z q) p p) p z q))))) |
58 | 58 | = (a d (r 100 200) 200 (100 (z 200) 100 100) 100 z 200) |
0 | (robin (0 . 1) (small (0 . 1) | |
1 | arith (0 . 1) | |
2 | list (0 . 1) | |
3 | concurrency (0 . 1) | |
4 | console (0 . 1)) | |
0 | (robin (0 1) ((small (0 1) *) | |
1 | (arith (0 1) *) | |
2 | (list (0 1) *) | |
3 | (concurrency (0 1) *) | |
4 | (console (0 1) *)) | |
5 | 5 | (let ( |
6 | 6 | (loop! (fun (self x) |
7 | 7 | (if (equal? x 10000) |
0 | (robin (0 . 1) (small (0 . 1) | |
1 | list (0 . 1) | |
2 | boolean (0 . 1) | |
3 | concurrency (0 . 1) | |
4 | arith (0 . 1) | |
5 | random (0 . 1) | |
6 | crude-io (0 . 1) | |
7 | term (0 . 1)) | |
0 | (robin (0 1) ((small (0 1) *) | |
1 | (list (0 1) *) | |
2 | (boolean (0 1) *) | |
3 | (concurrency (0 1) *) | |
4 | (arith (0 1) *) | |
5 | (random (0 1) *) | |
6 | (crude-io (0 1) *) | |
7 | (term (0 1) *)) | |
8 | 8 | ;''Beginnings of an implementation of Hunt the Wumpus. |
9 | 9 | The !'s aren't quite consistent in this yet.'' |
10 | 10 | (let |
0 | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1) crude-io (0 . 1)) | |
0 | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *) (crude-io (0 1) *)) | |
1 | 1 | (call! crude-input subscribe () x |
2 | 2 | (recv! entered |
3 | 3 | (pair (literal i-got) entered)))) |
0 | (robin (0 . 1) (small (0 . 1) concurrency (0 . 1) crude-io (0 . 1)) | |
0 | (robin (0 1) ((small (0 1) *) (concurrency (0 1) *) (crude-io (0 1) *)) | |
1 | 1 | (bind input-loop |
2 | 2 | (fun (self) |
3 | 3 | (recv! entered |
0 | (robin (0 . 1) (pure (0 . 1)) | |
0 | (robin (0 1) ((pure (0 1) *)) | |
1 | 1 | (pure? (env) (literal (foo)) (literal (macro (self args env) foo)))) |
0 | (robin (0 . 1) (small (0 . 1) list (0 . 1) concurrency (0 . 1) crude-io (0 . 1) random (0 . 1)) | |
0 | (robin (0 1) ((small (0 1) *) | |
1 | (list (0 1) *) | |
2 | (concurrency (0 1) *) | |
3 | (crude-io (0 1) *) | |
4 | (random (0 1) *)) | |
1 | 5 | (bind output-loop |
2 | 6 | (fun (self n) |
3 | 7 | (if (equal? n 0) |
0 | (robin (0 . 1) (small (0 . 1) | |
1 | exception (0 . 1) | |
2 | concurrency (0 . 1) | |
3 | crude-io (0 . 1) | |
4 | env (0 . 1)) | |
0 | (robin (0 1) ((small (0 1) *) | |
1 | (exception (0 1) *) | |
2 | (concurrency (0 1) *) | |
3 | (crude-io (0 1) *) | |
4 | (env (0 1) *)) | |
5 | 5 | (let ( |
6 | 6 | (restricted-env |
7 | 7 | (export pair head tail if equal? pair? macro? symbol? boolean? |
0 | (robin (0 . 1) (small (0 . 1) env (0 . 1)) | |
0 | (robin (0 1) ((small (0 1) *) (env (0 1) *)) | |
1 | 1 | (let ( |
2 | 2 | (- (fun (a b) |
3 | 3 | (subtract a b))) |
0 | (robin (0 . 1) (small (0 . 1) env (0 . 1) arith (0 . 1)) | |
0 | (robin (0 1) ((small (0 1) *) (env (0 1) *) (arith (0 1) *)) | |
1 | 1 | (let ( |
2 | 2 | (assert (macro (self args env) |
3 | 3 | (let ((expr (head args)) |
0 | (robin (0 . 1) (small (0 . 1) env (0 . 1)) | |
0 | (robin (0 1) ((small (0 1) *) (env (0 1) *)) | |
1 | 1 | (let ( |
2 | 2 | (and (macro (self args env) |
3 | 3 | (if (equal? args ()) |
0 | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
0 | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
1 | 1 | (let ( |
2 | 2 | (env? (fun (li) |
3 | 3 | (bind env?-r (fun (self li) |
0 | (robin (0 . 1) (small (0 . 1)) | |
0 | (robin (0 1) ((small (0 1) *)) | |
1 | 1 | (let ( |
2 | 2 | (empty? (fun (li) |
3 | 3 | (equal? li ()))) |
0 | (robin (0 . 1) (small (0 . 1) list (0 . 1) env (0 . 1)) | |
0 | (robin (0 1) ((small (0 1) *) (list (0 1) *) (env (0 1) *)) | |
1 | 1 | ;''This is an EXPERIMENTAL module for EXPERIMENTING with |
2 | 2 | static analysis in Robin using metadata on values.'' |
3 | 3 | (let ( |
0 | (robin (0 . 1) (core (0 . 1)) | |
0 | (robin (0 1) ((core (0 1) *)) | |
1 | 1 | (eval |
2 | 2 | (pair |
3 | 3 | (pair ((macro (self args env) (head args)) literal) (macro (self args env) (head args))) |
0 | (robin (0 . 1) (small (0 . 1) list (0 . 1)) | |
0 | (robin (0 1) ((small (0 1) *) (list (0 1) *)) | |
1 | 1 | (let ( |
2 | 2 | (subst (fun (src dest sexp) |
3 | 3 | (bind subst-r (fun (self src dest sexp) |
27 | 27 | -c "Interpret Bundled Robin Program" \ |
28 | 28 | -c "Interpret Robin Program without output" \ |
29 | 29 | -f 'Interpret Robin Program:shell command "bin\\robin.exe %(test-file)"' \ |
30 | -f 'Interpret Bundled Robin Program:shell command "python bin\\unbundle_modules.py %(test-file)"' \ | |
30 | -f 'Interpret Bundled Robin Program:shell command "c:\\Python27\\python.exe bin\\unbundle_modules.py %(test-file)"' \ | |
31 | 31 | -f 'Interpret Robin Program without output:shell command "bin\\robin.exe -n %(test-file)"' \ |
32 | 32 | ${FILES} |
33 | 33 | rm -f results* |