Checkpoint removing `self`. list, choose, remainder need rewriting.
Chris Pressey
4 years ago
61 | 61 | Such a form is parsed as a conventional string data type (see |
62 | 62 | the "String" section in the Robin Expression Language for details.) |
63 | 63 | |
64 | | (define literal (macro (s a e) (head a))) | |
64 | | (define literal (macro (a e) (head a))) | |
65 | 65 | | (display |
66 | 66 | | (literal ''Hello'')) |
67 | 67 | = (72 101 108 108 111) |
68 | 68 | |
69 | 69 | A single single quote may appear in string literals of this kind. |
70 | 70 | |
71 | | (define literal (macro (s a e) (head a))) | |
71 | | (define literal (macro (a e) (head a))) | |
72 | 72 | | (display |
73 | 73 | | (literal ''He'llo'')) |
74 | 74 | = (72 101 39 108 108 111) |
78 | 78 | match the sentinel given between the trailing single quote pair. The |
79 | 79 | sentinel may consist of any text not containing a single quote. |
80 | 80 | |
81 | | (define literal (macro (s a e) (head a))) | |
81 | | (define literal (macro (a e) (head a))) | |
82 | 82 | | (display |
83 | 83 | | (literal 'X'Hello'X')) |
84 | 84 | = (72 101 108 108 111) |
85 | 85 | |
86 | | (define literal (macro (s a e) (head a))) | |
86 | | (define literal (macro (a e) (head a))) | |
87 | 87 | | (display |
88 | 88 | | (literal '...('Hello'...(')) |
89 | 89 | = (72 101 108 108 111) |
90 | 90 | |
91 | | (define literal (macro (s a e) (head a))) | |
91 | | (define literal (macro (a e) (head a))) | |
92 | 92 | | (display |
93 | 93 | | (literal 'X'Hello'Y')) |
94 | 94 | ? unexpected end of input |
95 | 95 | |
96 | 96 | A sentinelized literal like this may embed a pair of single quotes. |
97 | 97 | |
98 | | (define literal (macro (s a e) (head a))) | |
98 | | (define literal (macro (a e) (head a))) | |
99 | 99 | | (display |
100 | 100 | | (literal 'X'Hel''lo'X')) |
101 | 101 | = (72 101 108 39 39 108 111) |
103 | 103 | By choosing different sentinels, string literals may contain any other |
104 | 104 | string literal. |
105 | 105 | |
106 | | (define literal (macro (s a e) (head a))) | |
106 | | (define literal (macro (a e) (head a))) | |
107 | 107 | | (display |
108 | 108 | | (literal 'X'Hel'Y'bye'Y'lo'X')) |
109 | 109 | = (72 101 108 39 89 39 98 121 101 39 89 39 108 111) |
112 | 112 | (Functions to convert escape sequences commonly found in other languages |
113 | 113 | may one day be available in a standard module.) |
114 | 114 | |
115 | | (define literal (macro (s a e) (head a))) | |
115 | | (define literal (macro (a e) (head a))) | |
116 | 116 | | (display |
117 | 117 | | (literal ''Hello\nworld'')) |
118 | 118 | = (72 101 108 108 111 92 110 119 111 114 108 100) |
120 | 120 | All characters which appear in the source text between the delimiters |
121 | 121 | of the string literal are literally included in the string. |
122 | 122 | |
123 | | (define literal (macro (s a e) (head a))) | |
123 | | (define literal (macro (a e) (head a))) | |
124 | 124 | | (display |
125 | 125 | | (literal ''Hello |
126 | 126 | | world'')) |
128 | 128 | |
129 | 129 | Adjacent string literals are not automatically concatenated. |
130 | 130 | |
131 | | (define literal (macro (s a e) (head a))) | |
131 | | (define literal (macro (a e) (head a))) | |
132 | 132 | | (display |
133 | 133 | | (literal (''Hello'' ''world''))) |
134 | 134 | = ((72 101 108 108 111) (119 111 114 108 100)) |
258 | 258 | covered yet: a macro. We'll just go ahead and show the example, and |
259 | 259 | will explain macros later. |
260 | 260 | |
261 | | ((macro (s a e) (head a)) hello) | |
261 | | ((macro (a e) (head a)) hello) | |
262 | 262 | = hello |
263 | 263 | |
264 | 264 | A Robin implementation is not expected to be able to generate new symbols |
332 | 332 | binds each of those values to a formal parameter of the function, then |
333 | 333 | evaluates the body of the function in that new environment, a macro: |
334 | 334 | |
335 | * binds the macro value itself to the first formal parameter of the | |
336 | macro (by convention called `self`) — this is to facilitate writing | |
337 | recursive macros; | |
338 | 335 | * binds the literal tail of the list of the macro application to |
339 | 336 | the second formal parameter of the macro (by convention called `args`); |
340 | 337 | * binds a binding alist representing the environment in effect at the |
349 | 346 | Macros are represented as the S-expression expansion of their |
350 | 347 | implementation. |
351 | 348 | |
352 | | (macro (self args env) args) | |
353 | = (macro (self args env) args) | |
349 | | (macro (args env) args) | |
350 | = (macro (args env) args) | |
354 | 351 | |
355 | 352 | Macros can be applied, and that is the typical use of them. |
356 | 353 | |
357 | | ((macro (self args env) args) 1) | |
354 | | ((macro (args env) args) 1) | |
358 | 355 | = (1) |
359 | 356 | |
360 | 357 | ### Lists ### |
380 | 377 | |
381 | 378 | Non-empty lists do not evaluate to themselves; rather, they represent a macro |
382 | 379 | application. However, the `literal` macro (whose definition is |
383 | `(macro (s a e) (head a))`) may be used to obtain a literal list. | |
384 | ||
385 | | ((macro (s a e) (head a)) (7 8))) | |
380 | `(macro (a e) (head a))`) may be used to obtain a literal list. | |
381 | ||
382 | | ((macro (a e) (head a)) (7 8))) | |
386 | 383 | = (7 8) |
387 | 384 | |
388 | 385 | Lists cannot be directly applied, but since a list itself represents an |
672 | 669 | is perhaps not the best example.) |
673 | 670 | |
674 | 671 | | (define true #t) |
675 | | (define true ((macro (self args env) #t))) | |
672 | | (define true ((macro (args env) #t))) | |
676 | 673 | | (display true) |
677 | 674 | = #t |
678 | 675 | |
825 | 822 | the integer 0, and the state is set to 0 after each event is reacted to. |
826 | 823 | |
827 | 824 | | (reactor (line-terminal) 0 |
828 | | (macro (self args env) | |
825 | | (macro (args env) | |
829 | 826 | | (bind event (head args) |
830 | 827 | | (bind event-type (head event) |
831 | 828 | | (if (equal? event-type (literal init)) |
845 | 842 | Thus we can construct a simple `cat` program: |
846 | 843 | |
847 | 844 | | (reactor (line-terminal) 0 |
848 | | (macro (self args env) | |
845 | | (macro (args env) | |
849 | 846 | | (bind event (head args) |
850 | 847 | | (bind event-type (head event) |
851 | 848 | | (bind event-payload (head (tail event)) |
880 | 877 | A reactor can issue multiple commands in its response to an event. |
881 | 878 | |
882 | 879 | | (reactor (line-terminal) 0 |
883 | | (macro (self args env) | |
880 | | (macro (args env) | |
884 | 881 | | (bind event (head args) |
885 | 882 | | (bind event-type (head event) |
886 | 883 | | (bind event-payload (head (tail event)) |
900 | 897 | message of some kind, but it should otherwise ignore it and keep going. |
901 | 898 | |
902 | 899 | | (reactor (line-terminal) 0 |
903 | | (macro (self args env) | |
900 | | (macro (args env) | |
904 | 901 | | (bind event (head args) |
905 | 902 | | (bind event-type (head event) |
906 | 903 | | (bind event-payload (head (tail event)) |
924 | 921 | but this is not a strict requirement. |
925 | 922 | |
926 | 923 | | (reactor (line-terminal) 0 |
927 | | (macro (self args env) | |
924 | | (macro (args env) | |
928 | 925 | | (bind event (head args) |
929 | 926 | | (bind event-type (head event) |
930 | 927 | | (bind event-payload (head (tail event)) |
943 | 940 | |
944 | 941 | Reactors can keep state. |
945 | 942 | |
946 | | (define inc (macro (self args env) | |
943 | | (define inc (macro (args env) | |
947 | 944 | | (subtract (eval env (head args)) (subtract 0 1)))) |
948 | 945 | | (reactor (line-terminal) 65 |
949 | | (macro (self args env) | |
946 | | (macro (args env) | |
950 | 947 | | (bind state (head (tail args)) |
951 | 948 | | (bind event (head args) |
952 | 949 | | (bind event-type (head event) |
964 | 961 | Multiple reactors can be instantiated, will react to the same events. |
965 | 962 | Note that reactors react in the *opposite* order they were installed. |
966 | 963 | |
967 | | (define inc (macro (self args env) | |
964 | | (define inc (macro (args env) | |
968 | 965 | | (subtract (eval env (head args)) (subtract 0 1)))) |
969 | 966 | | (reactor (line-terminal) 65 |
970 | | (macro (self args env) | |
967 | | (macro (args env) | |
971 | 968 | | (bind state (head (tail args)) |
972 | 969 | | (bind event (head args) |
973 | 970 | | (bind event-type (head event) |
976 | 973 | | (list (inc state) (list (literal writeln) (list state))) |
977 | 974 | | (list state)))))))) |
978 | 975 | | (reactor (line-terminal) 0 |
979 | | (macro (self args env) | |
976 | | (macro (args env) | |
980 | 977 | | (bind event (head args) |
981 | 978 | | (bind event-type (head event) |
982 | 979 | | (bind event-payload (head (tail event)) |
996 | 993 | |
997 | 994 | A reactor can stop by issuing a `stop` command. |
998 | 995 | |
999 | | (define inc (macro (self args env) | |
996 | | (define inc (macro (args env) | |
1000 | 997 | | (subtract (eval env (head args)) (subtract 0 1)))) |
1001 | 998 | | (reactor (line-terminal) 65 |
1002 | | (macro (self args env) | |
999 | | (macro (args env) | |
1003 | 1000 | | (bind state (head (tail args)) |
1004 | 1001 | | (bind event (head args) |
1005 | 1002 | | (bind event-type (head event) |
1020 | 1017 | |
1021 | 1018 | Stopping one reactor does not stop others. |
1022 | 1019 | |
1023 | | (define inc (macro (self args env) | |
1020 | | (define inc (macro (args env) | |
1024 | 1021 | | (subtract (eval env (head args)) (subtract 0 1)))) |
1025 | 1022 | | (reactor (line-terminal) 65 |
1026 | | (macro (self args env) | |
1023 | | (macro (args env) | |
1027 | 1024 | | (bind state (head (tail args)) |
1028 | 1025 | | (bind event (head args) |
1029 | 1026 | | (bind event-type (head event) |
1034 | 1031 | | (list (inc state) (list (literal writeln) event-payload))) |
1035 | 1032 | | (list state)))))))) |
1036 | 1033 | | (reactor (line-terminal) 65 |
1037 | | (macro (self args env) | |
1034 | | (macro (args env) | |
1038 | 1035 | | (bind state (head (tail args)) |
1039 | 1036 | | (bind event (head args) |
1040 | 1037 | | (bind event-type (head event) |
0 | 0 | (require fun) |
1 | 1 | (require empty?) |
2 | 2 | |
3 | (define command (macro (self args env) | |
3 | (define command (macro (args env) | |
4 | 4 | (list (head args) (eval env (head (tail args)))))) |
5 | 5 | |
6 | (reactor (line-terminal) (list 0 0) (macro (self args env) | |
6 | (reactor (line-terminal) (list 0 0) (macro (args env) | |
7 | 7 | (let ((event (head args)) |
8 | 8 | (event-type (head event)) |
9 | 9 | (event-payload (head (tail event))) |
0 | 0 | (require bind) |
1 | 1 | |
2 | 2 | (reactor (line-terminal) 0 |
3 | (macro (self args env) | |
3 | (macro (args env) | |
4 | 4 | (bind event (head args) |
5 | 5 | (bind event-type (head event) |
6 | 6 | (bind event-payload (head (tail event)) |
4 | 4 | (require itoa) |
5 | 5 | |
6 | 6 | (reactor (line-terminal) 0 |
7 | (macro (self args env) | |
7 | (macro (args env) | |
8 | 8 | (bind event (head args) |
9 | 9 | (bind event-type (head event) |
10 | 10 | (bind event-payload (head (tail event)) |
15 | 15 | (if (equal? prev-state 256) |
16 | 16 | 0 |
17 | 17 | prev-state)) |
18 | (bind prompt (macro (self args env) | |
18 | (bind prompt (macro (args env) | |
19 | 19 | (bind show (eval env (head args)) |
20 | 20 | (bind state (eval env (head (tail args))) |
21 | 21 | (if show |
1 | 1 | (require literal) |
2 | 2 | |
3 | 3 | (reactor (line-terminal) 0 |
4 | (macro (self args env) | |
4 | (macro (args env) | |
5 | 5 | (bind event (head args) |
6 | 6 | (bind event-type (head event) |
7 | 7 | (if (equal? event-type (literal init)) |
3 | 3 | (require let) (require choose) (require itoa) (require abs) (require remainder) |
4 | 4 | |
5 | 5 | (reactor (line-terminal random-u16-source) 0 |
6 | (macro (self args env) | |
6 | (macro (args env) | |
7 | 7 | (let ((event (head args)) |
8 | 8 | (event-type (head event)) |
9 | 9 | (event-payload (head (tail event)))) |
70 | 70 | makeMacroEnv :: Env -> Expr -> Expr -> Env |
71 | 71 | makeMacroEnv env actuals m@(Macro closedEnv argList _) = |
72 | 72 | let |
73 | (List [(Symbol argSelf), (Symbol argFormal), | |
74 | (Symbol envFormal)]) = argList | |
75 | newEnv = insert argSelf m closedEnv | |
76 | newEnv' = insert argFormal actuals newEnv | |
73 | (List [(Symbol argFormal), (Symbol envFormal)]) = argList | |
74 | newEnv' = insert argFormal actuals closedEnv | |
77 | 75 | newEnv'' = insert envFormal env newEnv' |
78 | 76 | in |
79 | 77 | newEnv'' |
78 | 78 | eval_ env other cc = errMsg "illegal-arguments" other |
79 | 79 | |
80 | 80 | macro :: Evaluable |
81 | macro env (List [args@(List [(Symbol selfS), (Symbol argsS), (Symbol envS)]), body]) cc = | |
81 | macro env (List [args@(List [(Symbol argsS), (Symbol envS)]), body]) cc = | |
82 | 82 | cc $ Macro env args body |
83 | 83 | macro env other cc = errMsg "illegal-arguments" other |
84 | 84 |
26 | 26 | |
27 | 27 | '<<SPEC' |
28 | 28 | |
29 | (define abs (macro (self args env) | |
29 | (define abs (macro (args env) | |
30 | 30 | (bind-args (a) args env |
31 | 31 | (if (equal? (sign a) 1) a (subtract 0 a))))) |
25 | 25 | |
26 | 26 | '<<SPEC' |
27 | 27 | |
28 | (define add (macro (self args env) | |
28 | (define add (macro (args env) | |
29 | 29 | (bind-args (a b) args env |
30 | 30 | (subtract a (subtract 0 b))))) |
41 | 41 | |
42 | 42 | '<<SPEC' |
43 | 43 | |
44 | (define and (macro (self args env) | |
44 | (define and (macro (args env) | |
45 | 45 | (if (equal? (tail (tail args)) ()) |
46 | 46 | (if (eval env (head args)) |
47 | 47 | (if (eval env (head (tail args))) #t #f) |
44 | 44 | become clear here: typically you would just pass the macro's `args` and |
45 | 45 | `env` to those arguments. |
46 | 46 | |
47 | | (bind add (macro (self args env) | |
47 | | (bind add (macro (args env) | |
48 | 48 | | (bind-args (a b) args env |
49 | 49 | | (subtract a (subtract 0 b)))) |
50 | 50 | | (add 4 (add 5 6))) |
51 | 51 | = 15 |
52 | 52 | |
53 | | (bind add (macro (self args env) | |
53 | | (bind add (macro (args env) | |
54 | 54 | | (bind-args (a b) args env |
55 | 55 | | (subtract a (subtract 0 b)))) |
56 | 56 | | (bind r 7 |
57 | 57 | | (add r r))) |
58 | 58 | = 14 |
59 | 59 | |
60 | | (bind add (macro (self args env) | |
60 | | (bind add (macro (args env) | |
61 | 61 | | (bind-args (a b) args env |
62 | 62 | | (subtract a (subtract 0 b)))) |
63 | 63 | | (add (subtract 0 0))) |
64 | 64 | ? abort (illegal-arguments ((subtract 0 0))) |
65 | 65 | |
66 | | (bind add (macro (self args env) | |
66 | | (bind add (macro (args env) | |
67 | 67 | | (bind-args (a b) args env |
68 | 68 | | (subtract a (subtract 0 b)))) |
69 | 69 | | (add 9 9 9)) |
70 | 70 | ? abort (illegal-arguments (9 9 9)) |
71 | 71 | |
72 | | (bind add (macro (self args env) | |
72 | | (bind add (macro (args env) | |
73 | 73 | | (bind-args (a b) args env |
74 | 74 | | (subtract a (subtract 0 b)))) |
75 | 75 | | (add 1 n)) |
78 | 78 | '<<SPEC' |
79 | 79 | |
80 | 80 | (define bind-args |
81 | (macro (self args env) | |
81 | (macro (args env) | |
82 | 82 | (let ( |
83 | 83 | (id-list (head args)) |
84 | 84 | (orig-val-list (eval env (head (tail args)))) |
85 | 85 | (given-env (eval env (head (tail (tail args))))) |
86 | 86 | (expr (head (tail (tail (tail args))))) |
87 | (bind-args-r (macro (self args env) | |
87 | (bind-args-r (macro (args env) | |
88 | 88 | (let ( |
89 | (id-list (eval env (head args))) | |
90 | (val-list (eval env (head (tail args)))) | |
91 | (env-acc (eval env (head (tail (tail args))))) | |
89 | (self (eval env (head args))) | |
90 | (id-list (eval env (head (tail args)))) | |
91 | (val-list (eval env (head (tail (tail args))))) | |
92 | (env-acc (eval env (head (tail (tail (tail args)))))) | |
92 | 93 | ) |
93 | 94 | (if (equal? id-list ()) |
94 | 95 | (if (equal? val-list ()) |
105 | 106 | env-acc)) |
106 | 107 | error (abort error)))))))) |
107 | 108 | (recover |
108 | (bind-args-r id-list orig-val-list env) | |
109 | (bind-args-r bind-args-r id-list orig-val-list env) | |
109 | 110 | new-env (eval new-env expr) |
110 | 111 | error (abort error))))) |
9 | 9 | | (list x x)) |
10 | 10 | = (hello hello) |
11 | 11 | |
12 | | (bind dup (macro (self args env) | |
12 | | (bind dup (macro (args env) | |
13 | 13 | | (list (head args) (head args))) |
14 | 14 | | (dup g)) |
15 | 15 | = (g g) |
16 | 16 | |
17 | | (bind dup (macro (self args env) | |
17 | | (bind dup (macro (args env) | |
18 | 18 | | (bind x (eval env (head args)) |
19 | 19 | | (list x x))) |
20 | 20 | | (dup (literal g))) |
21 | 21 | = (g g) |
22 | 22 | |
23 | | (bind dup (macro (self args env) | |
23 | | (bind dup (macro (args env) | |
24 | 24 | | (bind x (eval env (head args)) |
25 | 25 | | (list x x))) |
26 | 26 | | (dup (dup (literal g)))) |
27 | 27 | = ((g g) (g g)) |
28 | 28 | |
29 | | (bind find (macro (self args env) | |
30 | | (bind-args (alist key) args env | |
31 | | (if (equal? alist (literal ())) (literal ()) | |
32 | | (if (equal? key (head (head alist))) | |
33 | | (head alist) | |
34 | | (self (tail alist) key))))) | |
35 | | (find (literal ((c d) (e f) (a b))) (literal a))) | |
36 | = (a b) | |
29 | /| (bind find (macro (self args env) | |
30 | /| (bind-args (alist key) args env | |
31 | /| (if (equal? alist (literal ())) (literal ()) | |
32 | /| (if (equal? key (head (head alist))) | |
33 | /| (head alist) | |
34 | /| (self (tail alist) key))))) | |
35 | /| (find (literal ((c d) (e f) (a b))) (literal a))) | |
36 | /= (a b) | |
37 | 37 | |
38 | 38 | `bind` expects exactly three arguments, or else an abort value will be produced. |
39 | 39 | |
51 | 51 | |
52 | 52 | '<<SPEC' |
53 | 53 | |
54 | (define bind (macro (self args env) | |
54 | (define bind (macro (args env) | |
55 | 55 | (eval |
56 | 56 | (prepend |
57 | 57 | (prepend (head args) (prepend (eval env (head (tail args))) |
24 | 24 | |
25 | 25 | '<<SPEC' |
26 | 26 | |
27 | (define boolean? (macro (self args env) | |
27 | (define boolean? (macro (args env) | |
28 | 28 | (bind-args (b) args env |
29 | 29 | (if (equal? b #t) |
30 | 30 | #t |
29 | 29 | |
30 | 30 | '<<SPEC' |
31 | 31 | |
32 | (define bound? (macro (self args env) | |
32 | (define bound? (macro (args env) | |
33 | 33 | (if (equal? args ()) |
34 | 34 | (abort (list (literal illegal-arguments) args)) |
35 | 35 | (if (equal? (tail args) ()) |
40 | 40 | |
41 | 41 | '<<SPEC' |
42 | 42 | |
43 | (define choose (macro (self args env) | |
43 | (define choose (macro (args env) | |
44 | 44 | (bind branch (head args) |
45 | 45 | (bind test (head branch) |
46 | 46 | (bind then (head (tail branch)) |
45 | 45 | |
46 | 46 | '<<SPEC' |
47 | 47 | |
48 | (define divide (macro (self args env) | |
48 | (define divide (macro (args env) | |
49 | 49 | (bind divide-r-pos (fun (self n d acc) ;(d is positive) |
50 | 50 | (if (gt? d n) |
51 | 51 | acc |
4 | 4 | `env` evaluates to all the bindings in effect at the point of execution |
5 | 5 | where this form is encountered, as an alist. |
6 | 6 | |
7 | | (bind find (macro (self args env) | |
8 | | (bind-args (alist key) args env | |
9 | | (if (equal? alist (literal ())) (literal ()) | |
10 | | (if (equal? key (head (head alist))) | |
11 | | (head alist) | |
12 | | (self (tail alist) key))))) | |
13 | | (prepend | |
14 | | (find (env) (literal symbol?)) (find (env) (literal prepend)))) | |
15 | = ((symbol? symbol?) prepend prepend) | |
7 | /| (bind find (macro (self args env) | |
8 | /| (bind-args (alist key) args env | |
9 | /| (if (equal? alist (literal ())) (literal ()) | |
10 | /| (if (equal? key (head (head alist))) | |
11 | /| (head alist) | |
12 | /| (self (tail alist) key))))) | |
13 | /| (prepend | |
14 | /| (find (env) (literal symbol?)) (find (env) (literal prepend)))) | |
15 | /= ((symbol? symbol?) prepend prepend) | |
16 | 16 | |
17 | 17 | `env` expects no arguments. Any arguments supplied will be simply ignored |
18 | 18 | and discarded, without being evaluated. |
19 | 19 | |
20 | | (bind find (macro (self args env) | |
21 | | (bind-args (alist key) args env | |
22 | | (if (equal? alist (literal ())) (literal ()) | |
23 | | (if (equal? key (head (head alist))) | |
24 | | (head alist) | |
25 | | (self (tail alist) key))))) | |
26 | | (prepend | |
27 | | (find (env find) (literal symbol?)) | |
28 | | (find (env (goofah whatever)) (literal prepend)))) | |
29 | = ((symbol? symbol?) prepend prepend) | |
20 | /| (bind find (macro (self args env) | |
21 | /| (bind-args (alist key) args env | |
22 | /| (if (equal? alist (literal ())) (literal ()) | |
23 | /| (if (equal? key (head (head alist))) | |
24 | /| (head alist) | |
25 | /| (self (tail alist) key))))) | |
26 | /| (prepend | |
27 | /| (find (env find) (literal symbol?)) | |
28 | /| (find (env (goofah whatever)) (literal prepend)))) | |
29 | /= ((symbol? symbol?) prepend prepend) | |
30 | 30 | |
31 | 31 | '<<SPEC' |
32 | 32 | |
33 | (define env (macro (self args env) env)) | |
33 | (define env (macro (args env) env)) |
35 | 35 | '<<SPEC' |
36 | 36 | |
37 | 37 | (define export |
38 | (macro (self args env) | |
38 | (macro (args env) | |
39 | 39 | (filter (fun (binding) (elem? (head binding) args)) env))) |
82 | 82 | |
83 | 83 | '<<SPEC' |
84 | 84 | |
85 | (define fun (macro (self args env) | |
86 | (bind extend-with-args (macro (self args env) | |
87 | (bind-args (env-to-extend formals actuals env-for-actuals) args env | |
85 | (define fun (macro (args env) | |
86 | (bind extend-with-args (macro (args env) | |
87 | (bind-args (self env-to-extend formals actuals env-for-actuals) args env | |
88 | 88 | (if (equal? formals ()) |
89 | 89 | (if (equal? actuals ()) |
90 | 90 | env-to-extend |
100 | 100 | (binding (list formal evaled-actual)) |
101 | 101 | (extended-env (prepend binding env-to-extend)) |
102 | 102 | ) |
103 | (self extended-env rest-formals rest-actuals env-for-actuals)))))) | |
104 | (macro (iself iargs ienv) | |
103 | (self self extended-env rest-formals rest-actuals env-for-actuals)))))) | |
104 | (macro (iargs ienv) | |
105 | 105 | (recover (extend-with-args env (head args) iargs ienv) |
106 | 106 | extended-env (eval extended-env (head (tail args))) |
107 | 107 | error (abort error)))))) |
52 | 52 | |
53 | 53 | '<<SPEC' |
54 | 54 | |
55 | (define gt? (macro (self args env) | |
56 | (bind cmp-same-sign? (macro (self args env) | |
55 | (define gt? (macro (args env) | |
56 | (bind cmp-same-sign? (macro (args env) | |
57 | 57 | (bind-args (a b c) args env |
58 | 58 | (equal? (sign (subtract a b)) c))) |
59 | 59 | (bind-args (a b) args env |
37 | 37 | |
38 | 38 | '<<SPEC' |
39 | 39 | |
40 | (define gte? (macro (self args env) | |
40 | (define gte? (macro (args env) | |
41 | 41 | (bind-args (a b) args env |
42 | 42 | (if (equal? a b) #t (gt? a b))))) |
24 | 24 | |
25 | 25 | '<<SPEC' |
26 | 26 | |
27 | (define itoa (macro (self args env) | |
28 | (bind itoa-r (macro (self args env) | |
29 | (bind-args (val) args env | |
27 | (define itoa (macro (args env) | |
28 | (bind itoa-r (macro (args env) | |
29 | (bind-args (self val) args env | |
30 | 30 | (if (equal? val 0) |
31 | 31 | () |
32 | 32 | (let ((digit (remainder val 10)) |
33 | 33 | (rest (divide val 10))) |
34 | (prepend (add 48 digit) (self rest)))))) | |
34 | (prepend (add 48 digit) (self self rest)))))) | |
35 | 35 | (bind-args (val) args env |
36 | 36 | (if (equal? val 0) |
37 | 37 | (list 48) |
38 | 38 | (if (lt? val 0) |
39 | (prepend 45 (reverse (itoa-r (subtract 0 val)))) | |
40 | (reverse (itoa-r val)))))))) | |
39 | (prepend 45 (reverse (itoa-r itoa-r (subtract 0 val)))) | |
40 | (reverse (itoa-r itoa-r val)))))))) |
15 | 15 | |
16 | 16 | `let` can bind a symbol to a macro. |
17 | 17 | |
18 | | (let ((a (macro (self args env) | |
18 | | (let ((a (macro (args env) | |
19 | 19 | | (let ((x (eval env (head args))) |
20 | 20 | | (y (eval env (head (tail args))))) |
21 | 21 | | (prepend y x))))) |
25 | 25 | Bindings established in a `let` remain in effect when evaluating |
26 | 26 | the arguments things in the body of the `let`. |
27 | 27 | |
28 | | (let ((dup (macro (self args env) | |
28 | | (let ((dup (macro (args env) | |
29 | 29 | | (bind x (eval env (head args)) |
30 | 30 | | (list x x))))) |
31 | 31 | | (dup (dup (literal g)))) |
96 | 96 | |
97 | 97 | '<<SPEC' |
98 | 98 | |
99 | (define let (macro (self args env) | |
99 | (define let (macro (args env) | |
100 | 100 | (bind bindings (head args) |
101 | 101 | (if (equal? bindings ()) |
102 | 102 | (eval env (head (tail args))) |
22 | 22 | |
23 | 23 | '<<SPEC' |
24 | 24 | |
25 | (define list (macro (self args env) | |
25 | (define list (macro (args env) | |
26 | 26 | (if (equal? args ()) |
27 | 27 | () |
28 | 28 | (prepend (eval env (head args)) |
52 | 52 | |
53 | 53 | '<<SPEC' |
54 | 54 | |
55 | (define lt? (macro (self args env) | |
56 | (bind cmp-same-sign? (macro (self args env) | |
55 | (define lt? (macro (args env) | |
56 | (bind cmp-same-sign? (macro (args env) | |
57 | 57 | (bind-args (a b c) args env |
58 | 58 | (equal? (sign (subtract a b)) c))) |
59 | 59 | (bind-args (a b) args env |
37 | 37 | |
38 | 38 | '<<SPEC' |
39 | 39 | |
40 | (define lte? (macro (self args env) | |
40 | (define lte? (macro (args env) | |
41 | 41 | (bind-args (a b) args env |
42 | 42 | (if (equal? a b) #t (lt? a b))))) |
6 | 6 | `macro?` evaluates its argument, then evaluates to `#t` if it is a macro, |
7 | 7 | or `#f` if it is not. |
8 | 8 | |
9 | | (macro? (macro (self args env) args)) | |
9 | | (macro? (macro (args env) args)) | |
10 | 10 | = #t |
11 | 11 | |
12 | 12 | Intrinsic macros are macros. |
16 | 16 | |
17 | 17 | Literal symbols are not macros, even if they're the name of one. |
18 | 18 | |
19 | | (macro? ((macro (self args env) (head args)) macro)) | |
19 | | (macro? ((macro (args env) (head args)) macro)) | |
20 | 20 | = #f |
21 | 21 | |
22 | 22 | Numbers are not macros. |
9 | 9 | value. |
10 | 10 | |
11 | 11 | When this macro value is evaluated, the first formal argument will |
12 | be bound to the macro itself, the second will be bound to the | |
13 | literal, unevaluated list of arguments passed to the macro, and the | |
14 | third will be bound to an alist representing the environment in | |
15 | effect at the point the macro value is evaluated. | |
12 | be bound to the literal, unevaluated list of arguments passed to the | |
13 | macro, and the second will be bound to an alist representing the | |
14 | environment in effect at the point the macro value is evaluated. | |
16 | 15 | |
17 | These formals are conventionally called `self`, `args`, and `env`, | |
16 | These formals are conventionally called `args` and `env`, | |
18 | 17 | but different names can be chosen in the `macro` definition, for |
19 | 18 | instance to avoid shadowing. |
20 | 19 | |
21 | 20 | `literal`, in fact, can be defined as a macro, and it is one of the |
22 | 21 | simplest possible macros that can be written: |
23 | 22 | |
24 | | ((macro (self args env) (head args)) (why hello there)) | |
23 | | ((macro (args env) (head args)) (why hello there)) | |
25 | 24 | = (why hello there) |
26 | 25 | |
27 | 26 | Another facility that can be defined simply by a macro is `env`: |
28 | 27 | |
29 | (define env (macro (s a e) e)) | |
28 | (define env (macro (a e) e)) | |
30 | 29 | |
31 | 30 | These tests are written against the "small" library, which defines |
32 | 31 | both of these symbols (and a few others such as `bind` and `let`). |
38 | 37 | |
39 | 38 | | ((let |
40 | 39 | | ((a (literal these-are)) |
41 | | (m (macro (self args env) (prepend a args)))) | |
40 | | (m (macro (args env) (prepend a args)))) | |
42 | 41 | | m) my args) |
43 | 42 | = (these-are my args) |
44 | 43 | |
45 | 44 | Macros can return macros. |
46 | 45 | |
47 | 46 | | (let |
48 | | ((mk (macro (self argsa env) | |
49 | | (macro (self argsb env) | |
47 | | ((mk (macro (argsa env) | |
48 | | (macro (argsb env) | |
50 | 49 | | (prepend (head argsb) argsa)))) |
51 | 50 | | (mk2 (mk vindaloo))) |
52 | 51 | | (mk2 chicken)) |
56 | 55 | |
57 | 56 | | (let |
58 | 57 | | ((args (literal a)) |
59 | | (b (macro (self args env) (prepend args args)))) | |
58 | | (b (macro (args env) (prepend args args)))) | |
60 | 59 | | (b 7)) |
61 | 60 | = ((7) 7) |
62 | 61 | |
63 | `self` is there to let you write recursive macros. The following | |
64 | example demonstrates this; it evaluates `(prepend b d)` in an environment | |
65 | where all the identifiers you list after `qqq` have been bound to 0. | |
62 | /`self` is there to let you write recursive macros. The following | |
63 | /example demonstrates this; it evaluates `(prepend b d)` in an environment | |
64 | /where all the identifiers you list after `qqq` have been bound to 0. | |
65 | / | |
66 | / | (bind qqq | |
67 | / | (macro (self args env) | |
68 | / | (if (equal? args ()) | |
69 | / | (eval env (literal (prepend b (prepend d ())))) | |
70 | / | (eval (prepend (prepend (head args) (prepend 0 ())) env) | |
71 | / | (prepend self (tail args))))) | |
72 | / | (bind b 1 (bind d 4 (qqq b c d)))) | |
73 | / = (0 0) | |
74 | / | |
75 | / | (bind qqq | |
76 | / | (macro (self args env) | |
77 | / | (if (equal? args ()) | |
78 | / | (eval env (literal (prepend b (prepend d ())))) | |
79 | / | (eval (prepend (prepend (head args) (prepend 0 ())) env) | |
80 | / | (prepend self (tail args))))) | |
81 | / | (bind b 1 (bind d 4 (qqq x y z)))) | |
82 | / = (1 4) | |
66 | 83 | |
67 | | (bind qqq | |
68 | | (macro (self args env) | |
69 | | (if (equal? args ()) | |
70 | | (eval env (literal (prepend b (prepend d ())))) | |
71 | | (eval (prepend (prepend (head args) (prepend 0 ())) env) | |
72 | | (prepend self (tail args))))) | |
73 | | (bind b 1 (bind d 4 (qqq b c d)))) | |
74 | = (0 0) | |
75 | ||
76 | | (bind qqq | |
77 | | (macro (self args env) | |
78 | | (if (equal? args ()) | |
79 | | (eval env (literal (prepend b (prepend d ())))) | |
80 | | (eval (prepend (prepend (head args) (prepend 0 ())) env) | |
81 | | (prepend self (tail args))))) | |
82 | | (bind b 1 (bind d 4 (qqq x y z)))) | |
83 | = (1 4) | |
84 | ||
85 | A recursive `macro` application doesn't have to be tail-recursive. | |
86 | ||
87 | | (bind make-env | |
88 | | (macro (self args env) | |
89 | | (if (equal? args ()) | |
90 | | () | |
91 | | (prepend (prepend (head args) | |
92 | | (prepend (eval env (head args)) ())) | |
93 | | (eval env | |
94 | | (prepend self (tail args)))))) | |
95 | | (bind b 1 (bind d 4 (make-env b d macro)))) | |
96 | = ((b 1) (d 4) (macro macro)) | |
84 | /A recursive `macro` application doesn't have to be tail-recursive. | |
85 | / | |
86 | / | (bind make-env | |
87 | / | (macro (self args env) | |
88 | / | (if (equal? args ()) | |
89 | / | () | |
90 | / | (prepend (prepend (head args) | |
91 | / | (prepend (eval env (head args)) ())) | |
92 | / | (eval env | |
93 | / | (prepend self (tail args)))))) | |
94 | / | (bind b 1 (bind d 4 (make-env b d macro)))) | |
95 | / = ((b 1) (d 4) (macro macro)) | |
97 | 96 | |
98 | 97 | `macro` expects exactly two arguments. |
99 | 98 | |
100 | | ((macro (self args env)) (why hello there)) | |
101 | ? abort (illegal-arguments ((self args env))) | |
99 | | ((macro (args env)) (why hello there)) | |
100 | ? abort (illegal-arguments ((args env))) | |
102 | 101 | |
103 | | ((macro (self args env) prepend prepend) (why hello there)) | |
104 | ? abort (illegal-arguments ((self args env) prepend prepend)) | |
102 | | ((macro (args env) prepend prepend) (why hello there)) | |
103 | ? abort (illegal-arguments ((args env) prepend prepend)) | |
105 | 104 | |
106 | `macro` expects its first argument to be a list of exactly three | |
105 | `macro` expects its first argument to be a list of exactly two | |
107 | 106 | symbols. |
108 | 107 | |
109 | 108 | | ((macro 100 prepend) (why hello there)) |
110 | 109 | ? abort (illegal-arguments (100 prepend)) |
111 | 110 | |
112 | | ((macro (self args) prepend) (why hello there)) | |
113 | ? abort (illegal-arguments ((self args) prepend)) | |
111 | | ((macro (args) prepend) (why hello there)) | |
112 | ? abort (illegal-arguments ((args) prepend)) | |
114 | 113 | |
115 | | ((macro (self args env foo) prepend) (why hello there)) | |
116 | ? abort (illegal-arguments ((self args env foo) prepend)) | |
117 | ||
118 | | ((macro (self args 99) prepend) (why hello there)) | |
119 | ? abort (illegal-arguments ((self args 99) prepend)) | |
114 | | ((macro (args env foo) prepend) (why hello there)) | |
115 | ? abort (illegal-arguments ((args env foo) prepend)) | |
120 | 116 | |
121 | 117 | '<<SPEC' |
122 | 118 |
13 | 13 | very productive. (Also, it exposes the implementation of `map`, so this |
14 | 14 | is not a very good test.) |
15 | 15 | |
16 | | (map (macro (self args env) args) (literal (three dog night))) | |
16 | | (map (macro (args env) args) (literal (three dog night))) | |
17 | 17 | = (((head li)) ((head li)) ((head li))) |
18 | 18 | |
19 | 19 | '<<SPEC' |
34 | 34 | |
35 | 35 | '<<SPEC' |
36 | 36 | |
37 | (define multiply (macro (self args env) | |
37 | (define multiply (macro (args env) | |
38 | 38 | (bind multiply-r (fun (self a b) ;(b must be positive) |
39 | 39 | (if (equal? b 1) |
40 | 40 | a |
25 | 25 | |
26 | 26 | '<<SPEC' |
27 | 27 | |
28 | (define not (macro (self args env) | |
28 | (define not (macro (args env) | |
29 | 29 | (bind-args (a) args env |
30 | 30 | (if a #f #t)))) |
41 | 41 | |
42 | 42 | '<<SPEC' |
43 | 43 | |
44 | (define or (macro (self args env) | |
44 | (define or (macro (args env) | |
45 | 45 | (if (equal? (tail (tail args)) ()) |
46 | 46 | (if (eval env (head args)) |
47 | 47 | #t |
32 | 32 | in the context of a `recover`, it will still be recovered. |
33 | 33 | |
34 | 34 | | (recover |
35 | | ((macro (self args env) (abort (literal (nasty-value 1111)))) joe) | |
35 | | ((macro (args env) (abort (literal (nasty-value 1111)))) joe) | |
36 | 36 | | value (list value #t) |
37 | 37 | | error (list error #f)) |
38 | 38 | = ((nasty-value 1111) #f) |
46 | 46 | |
47 | 47 | '<<SPEC' |
48 | 48 | |
49 | (define remainder (macro (self args env) | |
49 | (define remainder (macro (args env) | |
50 | 50 | (bind remainder-r-pos (fun (self n d acc) ;(d is positive) |
51 | 51 | (if (gt? d n) |
52 | 52 | n |
16 | 16 | '<<SPEC' |
17 | 17 | |
18 | 18 | (define sandbox |
19 | (macro (self args env) | |
19 | (macro (args env) | |
20 | 20 | (eval (filter (fun (binding) (elem? (head binding) (head args))) env) |
21 | 21 | (head (tail args))))) |
26 | 26 | '<<SPEC' |
27 | 27 | |
28 | 28 | (define unbind |
29 | (macro (self args env) | |
29 | (macro (args env) | |
30 | 30 | (eval (filter (fun (binding) (if (equal? (head binding) (head args)) #f #t)) env) |
31 | 31 | (head (tail args))))) |