├── .io.livecode.ch ├── _site │ └── index.html ├── defaults.json ├── install └── run ├── README ├── README.md ├── black-with-delta.scm ├── black.scm ├── break.blk ├── compare ├── env.scm ├── examples ├── church.scm ├── cnv.scm ├── instr.blk ├── instr2.blk ├── pal.scm ├── stack.scm ├── start.scm ├── taba.blk ├── taba2.blk ├── taba3.blk ├── transcript.scm └── utils.blk ├── init.scm ├── int.scm └── stream.scm /.io.livecode.ch/_site/index.html: -------------------------------------------------------------------------------- 1 | {% extends "base_livecode.html" %} 2 | 3 | {% block title %}The reflective language Black{% endblock %} 4 | 5 | {% block content %} 6 |

Warm up

7 | 8 |

Just like Scheme... at first.

9 |
10 | (+ 2 1) 11 | (define inc (lambda (x) (+ x 1))) 12 | (inc 2) 13 | ((lambda (x) (+ x 1)) 2) 14 | (map inc '(1 2 3)) 15 | (map (lambda (x) (+ x 1)) '(1 2 3)) 16 |
17 | 18 |

Error loads new meta level.

19 |
20 | (incr 2) 21 |
22 |

Notice the prompt change, from 0-7 to 1-0. 23 | The first number is the meta level, i.e. the n in metan level. The second number is just the iteration counter at this level.

24 | 25 |

Two ways to go back down.

26 | 27 |

(1) call old-cont.

28 |
29 | (old-cont (lambda (x) (+ x 1))) 30 |
31 |

(2) use (base-eval exp env cont).

32 |
33 | (base-eval 1 '() (lambda (v) v)) 34 | incr ;; typo again 35 | (base-eval 'inc old-env (lambda (v) v)) 36 | incr ;; typo again 37 | (base-eval 'inc old-env old-cont) 38 |
39 | 40 |

Notice we needed to quote inc at the meta-level. Why? 41 | Let's jump back to the meta1 level and see. 42 | We can jump levels normally with exit, no need to fake errors.

43 |
44 | (exit 'hello) 45 | 46 | ;; inc is not defined 47 | inc 48 |
49 | 50 |

Oh, we loaded meta2 now! Let's go back to 0:

51 |
52 | (old-cont 1) 53 | (old-cont 'back-to-user-level) 54 |
55 | 56 |

To recap, a variable is local to a level:

57 |
58 | (exit 'hello) 59 | (define foo 1) 60 | (old-cont foo) 61 | ;; foo is unbound at level 0 62 | foo 63 | ;; but at level 1, it is defined 64 | foo 65 | ;; going back again 66 | (old-cont foo) 67 |
68 | 69 |

Can we access some meta level without pushing away (or popping? which way does it go?) without leaving the level? Yes, with EM.

70 |
71 | (EM foo) 72 | (EM (define bar 2)) 73 | (EM bar) 74 | bar ;; not bound 75 | 76 | (EM (EM 1)) 77 | (EM (EM foo)) 78 | ;; oops, we just loaded level 3 79 | (old-cont 1) 80 |
81 |

Interesting, we got straight back to 0 from 3, some jumping indeed!

82 | 83 |

The Mystery of Meta-Continuations Revealed

84 | 85 |

Each level in the tower has its own environment and continuation.

86 | 87 |

Bouncing Up and Down

88 | 89 |

First, we redefine evaluation of variable (by mutating the meta 90 | level) so that when the variable name is _dummy we do 91 | something special: we call the continuation first with 1, then 2, then 3.

92 |
93 | (EM (begin 94 | (define old-eval-var eval-var) 95 | (set! eval-var (lambda (e r k) 96 | (if (eq? '_dummy e) (begin (k 1) (k 2) (k 3)) 97 | (old-eval-var e r k)))) 98 | )) 99 |
100 | 101 |

What happens when we evaluate _dummy?

102 |
103 | _dummy 104 |
105 | 106 |

OK, so it seems that it just jumps out at the first 1? Not so fast:

107 |
108 | _dummy ;; 1 109 | (exit 'up) ;; 2 110 | (exit 'up) ;; 3 111 | (exit 'up) ;; up (meta level) 112 |
113 | 114 |

Being Pushy... Bug or Feature?

115 | 116 |
117 | (define where_am_i 'user) 118 | (EM (define where_am_i 'meta)) 119 | (EM (let ((old-eval-var eval-var) 120 | (__k (lambda (x) x))) 121 | (set! eval-var (lambda (e r k) 122 | (if (eq? e '__k) (k __k) 123 | (begin 124 | (if (eq? e '_) (set! __k k) '()) 125 | (old-eval-var e r k))))))) 126 | (define _ 0) 127 | (+ _ 1) 128 | where_am_i ;; user 129 | (EM where_am_i) ;; meta 130 | (__k 2) 131 | where_am_i ;; user 132 | (EM where_am_i) ;; user (!!!) 133 | (EM (EM where_am_i)) ;; meta 134 | (__k 2) ;; unbound variable __k 135 |
136 | 137 |

Further Reading

138 | 139 |

If you'd like to learn more about semantics of reflective towers, including pushy vs. jumpy continuations, see the paper 140 | Intensions and Extensions in a Reflective Tower (PDF) by Danvy et al.

141 | 142 |

Fun with Towers

143 | 144 |

The loaded code in the examples below is also on Github.

145 | 146 |

Counting Evaluations

147 | 148 |

Learn more about Church Encodings on Wikipedia. See also section 5.2 (Programming in the Lambda-Calculus) of Types and Programming Languages by Pierce.

149 | 150 |
151 | (exec-at-metalevel (load "examples/instr2.blk")) 152 | (load "examples/church.scm") 153 | (instr (prd c2)) 154 | (instr (prd-alt c2)) 155 | (instr (to_int (prd-alt c2))) 156 | (instr (to_int (prd c2))) 157 |
158 | 159 |

There and Back Again

160 | 161 |

There is a cute trick by Danvy et al. 162 | (ICFP, 163 | extended journal version) to construct (cnv xs ys) = (zip xs (reverse ys)) in n recursive calls and no auxiliary data list, where xs and ys are lists of size n.

164 | 165 |

It's fun to think about it, so let's not give it away. Suffice to 166 | say that it's helpful to visualize the stack.

167 |
168 | (EM (load "examples/utils.blk")) 169 | (EM (load "examples/taba.blk")) 170 | (load "examples/cnv.scm") 171 | (taba (cnv3 walk) (cnv3 '(1 2 3) '(a b c))) 172 | 173 | (load "examples/pal.scm") 174 | (taba (pal_c walk) (pal_c '(1 2 2 1))) 175 |
176 | 177 |
178 | (EM (load "examples/utils.blk")) 179 | (EM (load "examples/stack.scm")) 180 | (EM (load "examples/taba3.blk")) 181 | (load "examples/cnv.scm") 182 | (taba (cnv3 walk) (cnv3 '(1 2 3) '(a b c))) 183 | 184 | (load "examples/pal.scm") 185 | (taba (pal_c walk) (pal_c '(1 2 2 1))) 186 |
187 | 188 |

Your Turn

189 | 190 |
191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 |
210 | 211 |

Happy Happy Joy Joy!

212 | 213 | {% endblock %} 214 | -------------------------------------------------------------------------------- /.io.livecode.ch/defaults.json: -------------------------------------------------------------------------------- 1 | { 2 | "language" : "scheme" 3 | } 4 | -------------------------------------------------------------------------------- /.io.livecode.ch/install: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | echo OK -------------------------------------------------------------------------------- /.io.livecode.ch/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | echo "(load-option 'format)" >format.scm 5 | cat $2 $1 >out.scm 6 | mechanics-shell --load format.scm --load init.scm macro 75 | (lambda (x env) 76 | (let ((a (cadr x)) 77 | (b (caddr x))) 78 | `(cons ,a (delay ,b)))))) 79 | 80 | (define scheme-apply apply) 81 | (load "env.scm") 82 | (load "black.scm") or (load "black-with-delta.scm") 83 | (black) 84 | 85 | elk: 86 | (define head car) 87 | (define (tail x) (force (cdr x))) 88 | (define-macro (cons-stream a b) 89 | `(cons ,a (delay ,b))) 90 | (autoload 'pp 'pp) 91 | 92 | (define scheme-apply apply) 93 | (load "env.scm") 94 | (load "black.scm") or (load "black-with-delta.scm") 95 | (black) 96 | 97 | It seems that elk does not handle mutual tail recursion correctly. 98 | Thus, stack overflow will eventually occur. 99 | 100 | To quit Black, type an interrupt key. Black has no command to quit 101 | the system. (exit 0) will merely exit the current level. 102 | 103 | The extensions that are not described in the paper are as follows: 104 | 105 | 1. Special forms not described in the paper (cond, let, etc.) are 106 | supported. 107 | 108 | 2. Special forms delay, force, cons-stream, and primitive-EM are 109 | supported, so that the implementation is meta-circular. You can 110 | execute Black on top of Black by typing the followings in Black: 111 | 112 | (define head car) 113 | (define (tail x) (force (cdr x))) 114 | (load "env.scm") 115 | (load "black.scm") or (load "black-with-delta.scm") 116 | (black) 117 | 118 | 3. (if ) without is supported. 119 | 120 | 4. The error "Wrong number of arguments" (for lambda closures) is 121 | supported. 122 | 123 | When errors such as "Unbound variables" and "Not a Function" occur, 124 | the current level is properly terminated, and the control moves to the 125 | upper level. However, some errors cause the Black system to stop. 126 | Such errors include the ones occured in the application of primitives, 127 | e.g., (car 0). To handle these errors, we have to check if the 128 | application of primitives leads to an error every time a primitive is 129 | applied. Because it would make the apply procedure much longer and 130 | tedious, we do not remedy this but leave it as an alternative way to 131 | quit the Black system. 132 | 133 | For questions, comments, etc., contact asai@is.s.u-tokyo.ac.jp. 134 | 135 | References 136 | 137 | [1] Kenichi Asai, Satoshi Matsuoka, and Akinori Yonezawa 138 | "Duplication and Partial Evaluation 139 | --- For a Better Understanding of Reflective Languages ---" 140 | Lisp and Symbolic Computation, 9, pp.203-241, Kluwer Academic 141 | Publishers, Boston (1996). 142 | 143 | [2] Olivier Danvy and Karoline Malmkjaer 144 | "Intensions and Extensions in a Reflective Tower" 145 | Lisp and Functional Programming, pp.327-341 (1988). 146 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Black 2 | 3 | This is the source code for [Kenichi Asai](http://pllab.is.ocha.ac.jp/~asai/)'s Black programming language as described in the paper *Duplication and Partial Evaluation - For a Better Understanding of Reflective Languages*. Please see [the original README](/README) from the [black.tar.gz](http://pllab.is.ocha.ac.jp/~asai/papers/black.tar.gz) code archive accompanying the paper. 4 | 5 | # Getting Started 6 | 7 | ```scheme 8 | (load "env.scm") 9 | (load "stream.scm") 10 | (define scheme-apply apply) 11 | (load "black.scm") 12 | (black) 13 | ``` 14 | 15 | See the [examples](examples/transcript.scm). 16 | Play in your browser at [io.livecode.ch](http://io.livecode.ch/learn/readevalprintlove/black)! 17 | -------------------------------------------------------------------------------- /black-with-delta.scm: -------------------------------------------------------------------------------- 1 | (define scheme-apply apply) 2 | ; 3 | ; Eval functions 4 | ; 5 | (define (base-eval exp env cont) 6 | (cond ((number? exp) (meta-apply cont exp)) 7 | ((boolean? exp) (meta-apply cont exp)) 8 | ((string? exp) (meta-apply cont exp)) 9 | ((symbol? exp) (meta-apply 'eval-var exp env cont)) 10 | ((eq? (car exp) 'quote) (meta-apply 'eval-quote exp env cont)) 11 | ((eq? (car exp) 'if) (meta-apply 'eval-if exp env cont)) 12 | ((eq? (car exp) 'cond) (meta-apply 'eval-cond (cdr exp) env cont)) 13 | ((eq? (car exp) 'define) (meta-apply 'eval-define exp env cont)) 14 | ((eq? (car exp) 'set!) (meta-apply 'eval-set! exp env cont)) 15 | ((eq? (car exp) 'lambda) (meta-apply 'eval-lambda exp env cont)) 16 | ((eq? (car exp) 'delta) (meta-apply 'eval-delta exp env cont)) 17 | ((eq? (car exp) 'begin) (meta-apply 'eval-begin (cdr exp) env cont)) 18 | ((eq? (car exp) 'let) (meta-apply 'eval-let 19 | (car (cdr exp)) (cdr (cdr exp)) env cont)) 20 | ((eq? (car exp) 'let*) (meta-apply 'eval-let* 21 | (car (cdr exp)) (cdr (cdr exp)) env cont)) 22 | ((eq? (car exp) 'letrec) (meta-apply 'eval-letrec 23 | (car (cdr exp)) (cdr (cdr exp)) env cont)) 24 | ((eq? (car exp) 'EM) (meta-apply 'eval-EM exp env cont)) 25 | ((eq? (car exp) 'exec-at-metalevel) 26 | (meta-apply 'eval-EM exp env cont)) 27 | ((eq? (car exp) 'exit) (meta-apply 'eval-exit exp env cont)) 28 | ((eq? (car exp) 'load) (meta-apply 'eval-load exp env cont)) 29 | ((eq? (car exp) 'and) (meta-apply 'eval-and (cdr exp) env cont)) 30 | ((eq? (car exp) 'or) (meta-apply 'eval-or (cdr exp) env cont)) 31 | (else (meta-apply 'eval-application exp env cont)))) 32 | (define (eval-application exp env cont) 33 | (meta-apply 'base-eval (car exp) env 34 | (lambda (operator) 35 | (if (and (pair? operator) (eq? (car operator) delta-tag)) 36 | (meta-apply 'apply-delta operator (cdr exp) env cont) 37 | (meta-apply 'eval-list (cdr exp) env 38 | (lambda (operand) 39 | (meta-apply 'base-apply 40 | operator operand env cont))))))) 41 | (define (eval-var exp env cont) 42 | (let ((pair (get exp env))) 43 | (if (pair? pair) 44 | (meta-apply cont (cdr pair)) 45 | (meta-apply 'my-error 46 | (list 'eval-var: 'unbound 'variable: exp) env cont)))) 47 | (define (eval-quote exp env cont) (meta-apply cont (car (cdr exp)))) 48 | (define (eval-if exp env cont) 49 | (let ((pred-part (car (cdr exp))) 50 | (then-part (car (cdr (cdr exp)))) 51 | (else-part (cdr (cdr (cdr exp))))) 52 | (meta-apply 'base-eval pred-part env (lambda (p) 53 | (cond (p (meta-apply 'base-eval then-part env cont)) 54 | ((null? else-part) (meta-apply cont #f)) 55 | (else 56 | (meta-apply 'base-eval (car else-part) env cont))))))) 57 | (define (eval-cond clauses env cont) 58 | (cond ((null? clauses) (meta-apply cont '())) 59 | ((eq? (car (car clauses)) 'else) 60 | (meta-apply 'eval-begin (cdr (car clauses)) env cont)) 61 | (else 62 | (meta-apply 'base-eval 63 | (car (car clauses)) 64 | env 65 | (lambda (pred) 66 | (if pred 67 | (meta-apply 'eval-begin (cdr (car clauses)) 68 | env cont) 69 | (meta-apply 'eval-cond (cdr clauses) 70 | env cont))))))) 71 | (define (eval-define exp env cont) 72 | (if (pair? (car (cdr exp))) 73 | (let ((var (car (car (cdr exp)))) 74 | (body (cons 'lambda 75 | (cons (cdr (car (cdr exp))) 76 | (cdr (cdr exp)))))) 77 | (meta-apply 'base-eval body env 78 | (lambda (data) 79 | (define-value var data env) 80 | (meta-apply cont var)))) 81 | (let ((var (car (cdr exp))) 82 | (body (car (cdr (cdr exp))))) 83 | (meta-apply 'base-eval body env 84 | (lambda (data) 85 | (define-value var data env) 86 | (meta-apply cont var)))))) 87 | (define (eval-set! exp env cont) 88 | (let ((var (car (cdr exp))) 89 | (body (car (cdr (cdr exp))))) 90 | (meta-apply 'base-eval body env 91 | (lambda (data) 92 | (let ((pair (get var env))) 93 | (if (pair? pair) 94 | (begin (set-value! var data env) 95 | (meta-apply cont var)) 96 | (meta-apply 'my-error 97 | (list 'eval-set!: 'unbound 'variable var) 98 | env cont))))))) 99 | (define lambda-tag (cons 'lambda 'tag)) 100 | (define (eval-lambda exp env cont) 101 | (let ((lambda-body (cdr (cdr exp))) 102 | (lambda-params (car (cdr exp)))) 103 | (meta-apply cont (list lambda-tag lambda-params lambda-body env)))) 104 | (define delta-tag (cons 'delta 'tag)) 105 | (define (eval-delta exp env cont) 106 | (let ((delta-body (cdr (cdr exp))) 107 | (delta-params (car (cdr exp)))) 108 | (meta-apply cont (list delta-tag delta-params delta-body)))) 109 | (define (eval-begin body env cont) 110 | (define (eval-begin-local body) 111 | (if (null? (cdr body)) 112 | (meta-apply 'base-eval (car body) env cont) 113 | (meta-apply 'base-eval (car body) env 114 | (lambda (x) (eval-begin-local (cdr body)))))) 115 | (if (null? body) 116 | (meta-apply 'my-error '(eval-begin: null body) env cont) 117 | (eval-begin-local body))) 118 | (define (eval-let pairs body env cont) 119 | (let ((params (map car pairs)) 120 | (args (map (lambda (x) (car (cdr x))) pairs))) 121 | (meta-apply 'eval-list args env 122 | (lambda (operand) 123 | (meta-apply 'eval-begin body 124 | (extend env params operand) 125 | cont))))) 126 | (define (eval-let* pairs body env cont) 127 | (if (null? pairs) 128 | (meta-apply 'eval-begin body env cont) 129 | (meta-apply 'base-eval (car (cdr (car pairs))) env (lambda (arg) 130 | (meta-apply 'eval-let* (cdr pairs) body 131 | (extend env (list (car (car pairs))) (list arg)) 132 | cont))))) 133 | (define (eval-letrec pairs body env cont) 134 | (define (set-value-list! params operand env) 135 | (if (null? params) 136 | #f 137 | (begin (set-value! (car params) (car operand) env) 138 | (set-value-list! (cdr params) (cdr operand) env)))) 139 | (let ((params (map car pairs)) 140 | (args (map (lambda (x) (car (cdr x))) pairs))) 141 | (let ((letrec-env (extend env params params))) 142 | (meta-apply 'eval-list args letrec-env 143 | (lambda (operand) 144 | (set-value-list! params operand letrec-env) 145 | (meta-apply 'eval-begin body letrec-env cont)))))) 146 | (define (eval-EM exp env cont) 147 | (lambda (Mcont) 148 | (let ((meta-env (car (head Mcont))) 149 | (meta-cont (car (cdr (head Mcont)))) 150 | (meta-Mcont (tail Mcont))) 151 | ((meta-apply 'base-eval 152 | (car (cdr exp)) 153 | meta-env 154 | (lambda (ans) (lambda (Mcont2) 155 | ((meta-apply cont ans) 156 | (cons-stream (head Mcont) Mcont2))))) 157 | meta-Mcont)))) 158 | (define (eval-exit exp env cont) 159 | (meta-apply 'base-eval (car (cdr exp)) env 160 | (lambda (x) (meta-apply 'my-error x env cont)))) 161 | (define (eval-list exp env cont) 162 | (if (null? exp) 163 | (meta-apply cont '()) 164 | (meta-apply 'base-eval (car exp) env 165 | (lambda (val1) 166 | (meta-apply 'eval-list (cdr exp) env 167 | (lambda (val2) 168 | (meta-apply cont (cons val1 val2)))))))) 169 | (define (base-apply operator operand env cont) 170 | (cond ((procedure? operator) 171 | (cond ((eq? operator map) 172 | (meta-apply 'eval-map 173 | (car operand) (car (cdr operand)) env cont)) 174 | ((eq? operator scheme-apply) 175 | (meta-apply 'base-apply 176 | (car operand) (car (cdr operand)) env cont)) 177 | ((pair? (member operator primitive-procedures)) 178 | (meta-apply cont (scheme-apply operator operand))) 179 | (else ; called when going down a level. 180 | (lambda (Mcont) 181 | ((scheme-apply operator operand) 182 | (cons-stream (list (get-global-env env) cont) Mcont)))))) 183 | ((and (pair? operator) 184 | (eq? (car operator) lambda-tag)) 185 | (let ((lambda-params (car (cdr operator))) 186 | (lambda-body (car (cdr (cdr operator)))) 187 | (lambda-env (car (cdr (cdr (cdr operator)))))) 188 | (if (can-receive? lambda-params operand) 189 | (meta-apply 'eval-begin 190 | lambda-body 191 | (extend lambda-env lambda-params operand) 192 | cont) 193 | (meta-apply 'my-error 194 | (list 'base-apply: 'Wrong 'number 'of 'arguments: 195 | operand 'to: lambda-params) 196 | env cont)))) 197 | (else 198 | (meta-apply 'my-error (list 'Not 'a 'function: operator) env cont)))) 199 | (define (apply-delta operator operand env cont) 200 | (lambda (Mcont) 201 | (let ((meta-env (car (head Mcont))) 202 | (meta-cont (car (cdr (head Mcont)))) 203 | (meta-Mcont (tail Mcont))) 204 | (let ((delta-params (car (cdr operator))) 205 | (delta-body (car (cdr (cdr operator))))) 206 | ((meta-apply 'eval-begin 207 | delta-body 208 | (extend meta-env delta-params (list operand env cont)) 209 | meta-cont) 210 | meta-Mcont))))) 211 | (define old-env 0) 212 | (define old-cont 0) 213 | (define (my-error exp env cont) 214 | (lambda (Mcont) 215 | (let ((meta-env (car (head Mcont))) 216 | (meta-cont (car (cdr (head Mcont)))) 217 | (meta-Mcont (tail Mcont))) 218 | (set-value! 'old-env env meta-env) 219 | (set-value! 'old-cont cont meta-env) 220 | ((meta-apply meta-cont exp) meta-Mcont)))) 221 | (define (eval-load exp env cont) 222 | (define port (open-input-file (car (cdr exp)))) 223 | (define (load-local) 224 | (let ((input (read port))) 225 | (if (eof-object? input) 226 | (begin (close-input-port port) 227 | (meta-apply cont 'done)) 228 | (meta-apply 'base-eval input env 229 | (lambda (value) (load-local)))))) 230 | (load-local)) 231 | (define (eval-and body env cont) 232 | (cond ((null? body) (meta-apply cont #t)) 233 | ((null? (cdr body)) 234 | (meta-apply 'base-eval (car body) env cont)) 235 | (else 236 | (meta-apply 'base-eval (car body) env 237 | (lambda (result) 238 | (if result 239 | (meta-apply 'eval-and (cdr body) env cont) 240 | (meta-apply cont result))))))) 241 | (define (eval-or body env cont) 242 | (if (null? body) 243 | (meta-apply cont #f) 244 | (meta-apply 'base-eval (car body) env 245 | (lambda (result) 246 | (if result 247 | (meta-apply cont result) 248 | (meta-apply 'eval-or (cdr body) env cont)))))) 249 | ; 250 | ; Primitives 251 | ; 252 | (define (eval-map fun lst env cont) 253 | (if (null? lst) 254 | (meta-apply cont '()) 255 | (meta-apply 'base-apply fun (list (car lst)) env 256 | (lambda (x) (meta-apply 'eval-map fun (cdr lst) env 257 | (lambda (y) (meta-apply cont (cons x y)))))))) 258 | (define (primitive-procedure? . operand) 259 | (let ((arg (car operand))) 260 | (or (procedure? arg) 261 | (and (pair? arg) 262 | (eq? (car arg) lambda-tag))))) 263 | (define (primitive-output write args) 264 | (let ((answer (car args))) 265 | (if (and (pair? answer) 266 | (eq? (car answer) lambda-tag)) 267 | (let ((lambda-params (car (cdr answer))) 268 | (lambda-body (car (cdr (cdr answer)))) 269 | (lambda-env (car (cdr (cdr (cdr answer)))))) 270 | (write (cons 'lambda (cons lambda-params lambda-body)))) 271 | (write answer)))) 272 | (define (primitive-display . args) 273 | (primitive-output display args)) 274 | (define (primitive-write . args) 275 | (primitive-output write args)) 276 | (define (primitive-pp . args) 277 | (primitive-output pp args)) 278 | (define (primitive-print lst depth length) 279 | (define (print-sub lst d l top?) 280 | (cond ((pair? lst) 281 | (cond ((= l 0) 282 | (if top? (display "(...)") (display " ...)"))) 283 | ((= d 0) (display "#")) 284 | (else 285 | (if top? (display "(") (display " ")) 286 | (print-sub (car lst) (- d 1) length #t) 287 | (cond ((pair? (cdr lst)) 288 | (print-sub (cdr lst) d (- l 1) #f)) 289 | ((null? (cdr lst)) 290 | (display ")")) 291 | (else 292 | (begin (display " . ") 293 | (print-sub (cdr lst) d (- l 1) #f) 294 | (display ")"))))))) 295 | (else (display lst)))) 296 | (print-sub lst depth length #t)) 297 | ; 298 | ; Meta-apply 299 | ; 300 | (define (meta-apply proc-name-or-cont . operand) 301 | (lambda (Mcont) 302 | (let ((meta-env (car (head Mcont))) 303 | (meta-cont (car (cdr (head Mcont)))) 304 | (meta-Mcont (tail Mcont))) 305 | (let ((operator (if (symbol? proc-name-or-cont) 306 | (cdr (get proc-name-or-cont meta-env)) 307 | proc-name-or-cont))) 308 | (cond ((procedure? operator) 309 | (cond ((pair? (member operator primitive-procedures)) 310 | ((meta-apply 'base-apply operator operand meta-env meta-cont) 311 | meta-Mcont)) 312 | (else ; evaluator functions 313 | ((scheme-apply operator operand) Mcont)))) 314 | (else 315 | ((meta-apply 'base-apply operator operand meta-env meta-cont) 316 | meta-Mcont))))))) 317 | ; 318 | ; Initial Continuation 319 | ; 320 | (define (init-cont env level turn cont) 321 | (meta-apply cont 322 | (lambda (answer) 323 | (write level)(write '-)(write turn)(display ": ") 324 | (primitive-write answer) 325 | (newline) 326 | (write level)(write '-)(write (+ turn 1))(display "> ") 327 | (meta-apply 'base-eval (read) env 328 | (lambda (ans) 329 | (meta-apply 'init-cont env level (+ turn 1) 330 | (lambda (cont) (meta-apply cont ans)))))))) 331 | 332 | (define (run env level answer) 333 | (meta-apply 'init-cont env level 0 334 | (lambda (cont) (meta-apply cont answer)))) 335 | ; 336 | ; Environment 337 | ; 338 | ;(load "env.scm") 339 | ; 340 | ; Primitive Procedures 341 | ; 342 | (define primitive-procedures 343 | (list car cdr cons list pair? null? eq? eqv? equal? not set-car! set-cdr! 344 | append 345 | primitive-write primitive-pp primitive-display newline read 346 | primitive-print primitive-procedure? 347 | + - * / = < > quotient remainder number? 348 | boolean? string? symbol? assq member length 349 | open-input-file close-input-port eof-object? 350 | map scheme-apply 351 | make-pairs extend can-receive? get set-value! define-value 352 | search copy 353 | )) 354 | ; 355 | ; Initial Environment 356 | ; 357 | (define init-env (list (list 358 | (cons 'car car) 359 | (cons 'cdr cdr) 360 | (cons 'cons cons) 361 | (cons 'list list) 362 | (cons 'pair? pair?) 363 | (cons 'null? null?) 364 | (cons 'eq? eq?) 365 | (cons 'eqv? eqv?) 366 | (cons 'equal? equal?) 367 | (cons 'not not) 368 | (cons 'set-car! set-car!) 369 | (cons 'set-cdr! set-cdr!) 370 | (cons 'append append) 371 | (cons 'write primitive-write) 372 | (cons 'pp primitive-pp) 373 | (cons 'display primitive-display) 374 | (cons 'print primitive-print) 375 | (cons 'newline newline) 376 | (cons 'read read) 377 | (cons '+ +) 378 | (cons '- -) 379 | (cons '* *) 380 | (cons '/ /) 381 | (cons '= =) 382 | (cons '> >) 383 | (cons '< <) 384 | (cons 'quotient quotient) 385 | (cons 'remainder remainder) 386 | (cons 'number? number?) 387 | (cons 'boolean? boolean?) 388 | (cons 'string? string?) 389 | (cons 'symbol? symbol?) 390 | (cons 'procedure? primitive-procedure?) 391 | (cons 'assq assq) 392 | (cons 'member member) 393 | (cons 'length length) 394 | (cons 'open-input-file open-input-file) 395 | (cons 'close-input-port close-input-port) 396 | (cons 'eof-object? eof-object?) 397 | 398 | (cons 'map map) 399 | (cons 'scheme-apply scheme-apply) 400 | 401 | (cons 'empty-env empty-env) 402 | (cons 'make-pairs make-pairs) 403 | (cons 'extend extend) 404 | (cons 'can-receive? can-receive?) 405 | (cons 'get get) 406 | (cons 'set-value! set-value!) 407 | (cons 'define-value define-value) 408 | (cons 'search search) 409 | (cons 'copy copy) 410 | 411 | (cons 'base-eval base-eval) 412 | (cons 'eval-application eval-application) 413 | (cons 'eval-var eval-var) 414 | (cons 'eval-quote eval-quote) 415 | (cons 'eval-if eval-if) 416 | (cons 'eval-cond eval-cond) 417 | (cons 'eval-define eval-define) 418 | (cons 'eval-set! eval-set!) 419 | (cons 'lambda-tag lambda-tag) 420 | (cons 'eval-lambda eval-lambda) 421 | (cons 'delta-tag delta-tag) 422 | (cons 'eval-delta eval-delta) 423 | (cons 'eval-begin eval-begin) 424 | (cons 'eval-let eval-let) 425 | (cons 'eval-let* eval-let*) 426 | (cons 'eval-letrec eval-letrec) 427 | (cons 'eval-EM eval-EM) 428 | (cons 'eval-exit eval-exit) 429 | (cons 'eval-list eval-list) 430 | (cons 'base-apply base-apply) 431 | (cons 'apply-delta apply-delta) 432 | (cons 'my-error my-error) 433 | (cons 'eval-load eval-load) 434 | (cons 'eval-and eval-and) 435 | (cons 'eval-or eval-or) 436 | (cons 'eval-map eval-map) 437 | 438 | (cons 'init-env 0) ; to be filled when making a new level 439 | (cons 'init-cont init-cont) 440 | (cons 'run run) 441 | (cons 'primitive-procedures primitive-procedures) 442 | (cons 'old-env old-env) 443 | (cons 'old-cont old-cont) 444 | ))) 445 | ; 446 | ; Meta-level Initial Continuation 447 | ; 448 | ;(define (return result) 449 | ; (lambda (Mcont) 450 | ; (let ((meta-env (car (head Mcont))) 451 | ; (meta-cont (car (cdr (head Mcont)))) 452 | ; (meta-Mcont (tail Mcont))) 453 | ; ((meta-apply meta-cont result) 454 | ; meta-Mcont)))) 455 | (define (meta-init-cont env level supplied-env) 456 | (define-value 'init-env supplied-env env) ; share-env 457 | (display "New level loaded.")(newline) 458 | (lambda (result) 459 | (meta-apply 'run env level result))) 460 | ; 461 | ; Initial Meta-Continuation 462 | ; 463 | (define (init-Mcont level supplied-env) 464 | (let ((env (copy init-env))) 465 | (cons-stream (list env (meta-init-cont env level supplied-env)) 466 | (init-Mcont (+ level 1) env)))) 467 | ; 468 | ; Start up 469 | ; 470 | (define (black) 471 | (let* ((base-Mcont (init-Mcont 0 (copy init-env))) 472 | (env (car (head base-Mcont))) 473 | (cont (car (cdr (head base-Mcont)))) 474 | (Mcont (tail base-Mcont))) 475 | ((cont 'start) Mcont))) 476 | 477 | ;(newline) 478 | ;(black) 479 | -------------------------------------------------------------------------------- /black.scm: -------------------------------------------------------------------------------- 1 | ; 2 | ; Eval functions 3 | ; 4 | (define (base-eval exp env cont) 5 | (cond ((number? exp) (meta-apply cont exp)) 6 | ((boolean? exp) (meta-apply cont exp)) 7 | ((string? exp) (meta-apply cont exp)) 8 | ((symbol? exp) (meta-apply 'eval-var exp env cont)) 9 | ((eq? (car exp) 'quote) (meta-apply 'eval-quote exp env cont)) 10 | ((eq? (car exp) 'if) (meta-apply 'eval-if exp env cont)) 11 | ((eq? (car exp) 'cond) (meta-apply 'eval-cond (cdr exp) env cont)) 12 | ((eq? (car exp) 'define) (meta-apply 'eval-define exp env cont)) 13 | ((eq? (car exp) 'set!) (meta-apply 'eval-set! exp env cont)) 14 | ((eq? (car exp) 'lambda) (meta-apply 'eval-lambda exp env cont)) 15 | ((eq? (car exp) 'begin) (meta-apply 'eval-begin (cdr exp) env cont)) 16 | ((eq? (car exp) 'let) (meta-apply 'eval-let 17 | (car (cdr exp)) (cdr (cdr exp)) env cont)) 18 | ((eq? (car exp) 'let*) (meta-apply 'eval-let* 19 | (car (cdr exp)) (cdr (cdr exp)) env cont)) 20 | ((eq? (car exp) 'letrec) (meta-apply 'eval-letrec 21 | (car (cdr exp)) (cdr (cdr exp)) env cont)) 22 | ((eq? (car exp) 'EM) (meta-apply 'eval-EM exp env cont)) 23 | ((eq? (car exp) 'exec-at-metalevel) 24 | (meta-apply 'eval-EM exp env cont)) 25 | ((eq? (car exp) 'primitive-EM) 26 | (meta-apply 'eval-primitive-EM exp env cont)) 27 | ((eq? (car exp) 'exit) (meta-apply 'eval-exit exp env cont)) 28 | ((eq? (car exp) 'load) (meta-apply 'eval-load exp env cont)) 29 | ((eq? (car exp) 'and) (meta-apply 'eval-and (cdr exp) env cont)) 30 | ((eq? (car exp) 'or) (meta-apply 'eval-or (cdr exp) env cont)) 31 | ((eq? (car exp) 'delay) (meta-apply 'eval-delay exp env cont)) 32 | ((eq? (car exp) 'cons-stream) 33 | (meta-apply 'eval-cons-stream exp env cont)) 34 | (else (meta-apply 'eval-application exp env cont)))) 35 | (define (eval-application exp env cont) 36 | (meta-apply 'eval-list exp env 37 | (lambda (l) (meta-apply 'base-apply (car l) (cdr l) env cont)))) 38 | (define (eval-var exp env cont) 39 | (let ((pair (get exp env))) 40 | (if (pair? pair) 41 | (meta-apply cont (cdr pair)) 42 | (meta-apply 'my-error 43 | (list 'eval-var: 'unbound 'variable: exp) env cont)))) 44 | (define (eval-quote exp env cont) (meta-apply cont (car (cdr exp)))) 45 | (define (eval-if exp env cont) 46 | (let ((pred-part (car (cdr exp))) 47 | (then-part (car (cdr (cdr exp)))) 48 | (else-part (cdr (cdr (cdr exp))))) 49 | (meta-apply 'base-eval pred-part env (lambda (p) 50 | (cond (p (meta-apply 'base-eval then-part env cont)) 51 | ((null? else-part) (meta-apply cont #f)) 52 | (else 53 | (meta-apply 'base-eval (car else-part) env cont))))))) 54 | (define (eval-cond clauses env cont) 55 | (cond ((null? clauses) (meta-apply cont '())) 56 | ((eq? (car (car clauses)) 'else) 57 | (meta-apply 'eval-begin (cdr (car clauses)) env cont)) 58 | (else 59 | (meta-apply 'base-eval 60 | (car (car clauses)) 61 | env 62 | (lambda (pred) 63 | (if pred 64 | (meta-apply 'eval-begin (cdr (car clauses)) 65 | env cont) 66 | (meta-apply 'eval-cond (cdr clauses) 67 | env cont))))))) 68 | (define (eval-define exp env cont) 69 | (if (pair? (car (cdr exp))) 70 | (let ((var (car (car (cdr exp)))) 71 | (body (cons 'lambda 72 | (cons (cdr (car (cdr exp))) 73 | (cdr (cdr exp)))))) 74 | (meta-apply 'base-eval body env 75 | (lambda (data) 76 | (define-value var data env) 77 | (meta-apply cont var)))) 78 | (let ((var (car (cdr exp))) 79 | (body (car (cdr (cdr exp))))) 80 | (meta-apply 'base-eval body env 81 | (lambda (data) 82 | (define-value var data env) 83 | (meta-apply cont var)))))) 84 | (define (eval-set! exp env cont) 85 | (let ((var (car (cdr exp))) 86 | (body (car (cdr (cdr exp))))) 87 | (meta-apply 'base-eval body env 88 | (lambda (data) 89 | (let ((pair (get var env))) 90 | (if (pair? pair) 91 | (begin (set-value! var data env) 92 | (meta-apply cont var)) 93 | (meta-apply 'my-error 94 | (list 'eval-set!: 'unbound 'variable var) 95 | env cont))))))) 96 | (define lambda-tag (cons 'lambda 'tag)) 97 | (define (eval-lambda exp env cont) 98 | (let ((lambda-body (cdr (cdr exp))) 99 | (lambda-params (car (cdr exp)))) 100 | (meta-apply cont (list lambda-tag lambda-params lambda-body env)))) 101 | (define (eval-begin body env cont) 102 | (define (eval-begin-local body) 103 | (if (null? (cdr body)) 104 | (meta-apply 'base-eval (car body) env cont) 105 | (meta-apply 'base-eval (car body) env 106 | (lambda (x) (eval-begin-local (cdr body)))))) 107 | (if (null? body) 108 | (meta-apply 'my-error '(eval-begin: null body) env cont) 109 | (eval-begin-local body))) 110 | (define (eval-let pairs body env cont) 111 | (let ((params (map car pairs)) 112 | (args (map (lambda (x) (car (cdr x))) pairs))) 113 | (meta-apply 'eval-list args env 114 | (lambda (operand) 115 | (meta-apply 'eval-begin body 116 | (extend env params operand) 117 | cont))))) 118 | (define (eval-let* pairs body env cont) 119 | (if (null? pairs) 120 | (meta-apply 'eval-begin body env cont) 121 | (meta-apply 'base-eval (car (cdr (car pairs))) env (lambda (arg) 122 | (meta-apply 'eval-let* (cdr pairs) body 123 | (extend env (list (car (car pairs))) (list arg)) 124 | cont))))) 125 | (define (eval-letrec pairs body env cont) 126 | (define (set-value-list! params operand env) 127 | (if (null? params) 128 | #f 129 | (begin (set-value! (car params) (car operand) env) 130 | (set-value-list! (cdr params) (cdr operand) env)))) 131 | (let ((params (map car pairs)) 132 | (args (map (lambda (x) (car (cdr x))) pairs))) 133 | (let ((letrec-env (extend env params params))) 134 | (meta-apply 'eval-list args letrec-env 135 | (lambda (operand) 136 | (set-value-list! params operand letrec-env) 137 | (meta-apply 'eval-begin body letrec-env cont)))))) 138 | (define (eval-EM exp env cont) 139 | (lambda (Mcont) 140 | (let ((meta-env (car (head Mcont))) 141 | (meta-cont (car (cdr (head Mcont)))) 142 | (meta-Mcont (tail Mcont))) 143 | ((meta-apply 'base-eval 144 | (car (cdr exp)) 145 | meta-env 146 | (lambda (ans) (lambda (Mcont2) 147 | ((meta-apply cont ans) 148 | (cons-stream (head Mcont) Mcont2))))) 149 | meta-Mcont)))) 150 | (define (eval-primitive-EM exp env cont) 151 | (meta-apply 'base-eval (car (cdr exp)) env 152 | (lambda (body) (meta-apply 'eval-EM (list 'EM body) env cont)))) 153 | (define (eval-exit exp env cont) 154 | (meta-apply 'base-eval (car (cdr exp)) env 155 | (lambda (x) (meta-apply 'my-error x env cont)))) 156 | (define (eval-list exp env cont) 157 | (if (null? exp) 158 | (meta-apply cont '()) 159 | (meta-apply 'base-eval (car exp) env 160 | (lambda (val1) 161 | (meta-apply 'eval-list (cdr exp) env 162 | (lambda (val2) 163 | (meta-apply cont (cons val1 val2)))))))) 164 | (define (base-apply operator operand env cont) 165 | (cond ((procedure? operator) 166 | (cond ((eq? operator map) 167 | (meta-apply 'eval-map 168 | (car operand) (car (cdr operand)) env cont)) 169 | ((eq? operator scheme-apply) 170 | (meta-apply 'base-apply 171 | (car operand) (car (cdr operand)) env cont)) 172 | ((eq? operator force) 173 | (let ((arg (car operand))) 174 | (if (and (pair? arg) 175 | (eq? (car arg) delay-tag)) 176 | (let ((promise-body (car (cdr arg))) 177 | (promise-env (car (cdr (cdr arg)))) 178 | (pair (cdr (cdr arg)))) 179 | (if (pair? (cdr pair)) 180 | (meta-apply cont (car (cdr pair))) 181 | (meta-apply 'base-eval promise-body promise-env 182 | (lambda (ans) 183 | (set-cdr! pair (list ans)) 184 | (meta-apply cont ans))))) 185 | (meta-apply cont arg)))) 186 | ((pair? (member operator primitive-procedures)) 187 | (meta-apply cont (scheme-apply operator operand))) 188 | (else ; called when going down a level. 189 | (lambda (Mcont) 190 | ((scheme-apply operator operand) 191 | (cons-stream (list (get-global-env env) cont) Mcont)))))) 192 | ((and (pair? operator) 193 | (eq? (car operator) lambda-tag)) 194 | (let ((lambda-params (car (cdr operator))) 195 | (lambda-body (car (cdr (cdr operator)))) 196 | (lambda-env (car (cdr (cdr (cdr operator)))))) 197 | (if (can-receive? lambda-params operand) 198 | (meta-apply 'eval-begin 199 | lambda-body 200 | (extend lambda-env lambda-params operand) 201 | cont) 202 | (meta-apply 'my-error 203 | (list 'base-apply: 'Wrong 'number 'of 'arguments: 204 | operand 'to: lambda-params) 205 | env cont)))) 206 | (else 207 | (meta-apply 'my-error (list 'Not 'a 'function: operator) env cont)))) 208 | (define old-env 0) 209 | (define old-cont 0) 210 | (define (my-error exp env cont) 211 | (lambda (Mcont) 212 | (let ((meta-env (car (head Mcont))) 213 | (meta-cont (car (cdr (head Mcont)))) 214 | (meta-Mcont (tail Mcont))) 215 | (set-value! 'old-env env meta-env) 216 | (set-value! 'old-cont cont meta-env) 217 | ((meta-apply meta-cont exp) meta-Mcont)))) 218 | (define (eval-load exp env cont) 219 | (define port (open-input-file (car (cdr exp)))) 220 | (define (load-local) 221 | (let ((input (read port))) 222 | (if (eof-object? input) 223 | (begin (close-input-port port) 224 | (meta-apply cont 'done)) 225 | (meta-apply 'base-eval input env 226 | (lambda (value) (load-local)))))) 227 | (load-local)) 228 | (define (eval-and body env cont) 229 | (cond ((null? body) (meta-apply cont #t)) 230 | ((null? (cdr body)) 231 | (meta-apply 'base-eval (car body) env cont)) 232 | (else 233 | (meta-apply 'base-eval (car body) env 234 | (lambda (result) 235 | (if result 236 | (meta-apply 'eval-and (cdr body) env cont) 237 | (meta-apply cont result))))))) 238 | (define (eval-or body env cont) 239 | (if (null? body) 240 | (meta-apply cont #f) 241 | (meta-apply 'base-eval (car body) env 242 | (lambda (result) 243 | (if result 244 | (meta-apply cont result) 245 | (meta-apply 'eval-or (cdr body) env cont)))))) 246 | (define delay-tag (cons 'delay 'tag)) 247 | (define (eval-delay exp env cont) 248 | (let ((delay-body (car (cdr exp)))) 249 | (meta-apply cont (list delay-tag delay-body env)))) 250 | (define (eval-cons-stream exp env cont) 251 | (let ((car-part (car (cdr exp))) 252 | (cdr-part (car (cdr (cdr exp))))) 253 | (meta-apply 'base-eval (list 'cons car-part (list 'delay cdr-part)) 254 | env cont))) 255 | 256 | ; 257 | ; Primitives 258 | ; 259 | (define (eval-map fun lst env cont) 260 | (if (null? lst) 261 | (meta-apply cont '()) 262 | (meta-apply 'base-apply fun (list (car lst)) env 263 | (lambda (x) (meta-apply 'eval-map fun (cdr lst) env 264 | (lambda (y) (meta-apply cont (cons x y)))))))) 265 | (define (primitive-procedure? . operand) 266 | (let ((arg (car operand))) 267 | (or (procedure? arg) 268 | (and (pair? arg) 269 | (eq? (car arg) lambda-tag))))) 270 | (define (filter arg) 271 | (if (pair? arg) 272 | (cond ((eq? (car arg) lambda-tag) 273 | (let ((lambda-params (car (cdr arg))) 274 | (lambda-body (car (cdr (cdr arg))))) 275 | (cons 'lambda (cons lambda-params lambda-body)))) 276 | ((eq? (car arg) delay-tag) 277 | (let ((delay-body (car (cdr arg)))) 278 | (list ' delay-body))) 279 | (else 280 | (cons (filter (car arg)) 281 | (filter (cdr arg))))) 282 | arg)) 283 | (define (primitive-display . args) 284 | (display (filter (car args)))) 285 | (define (primitive-write . args) 286 | (write (filter (car args)))) 287 | (define (primitive-pp . args) 288 | (pp (filter (car args)))) 289 | (define (primitive-format . args) 290 | (apply format (map filter args))) 291 | (define (primitive-print lst depth length) 292 | (define (print-sub lst d l top?) 293 | (cond ((pair? lst) 294 | (cond ((= l 0) 295 | (if top? (display "(...)") (display " ...)"))) 296 | ((= d 0) (display "#")) 297 | (else 298 | (if top? (display "(") (display " ")) 299 | (print-sub (car lst) (- d 1) length #t) 300 | (cond ((pair? (cdr lst)) 301 | (print-sub (cdr lst) d (- l 1) #f)) 302 | ((null? (cdr lst)) 303 | (display ")")) 304 | (else 305 | (begin (display " . ") 306 | (print-sub (cdr lst) d (- l 1) #f) 307 | (display ")"))))))) 308 | (else (display lst)))) 309 | (print-sub lst depth length #t)) 310 | ; 311 | ; Meta-apply 312 | ; 313 | (define (meta-apply proc-name-or-cont . operand) 314 | (lambda (Mcont) 315 | (let* ((meta-env (car (head Mcont))) 316 | (meta-cont (car (cdr (head Mcont)))) 317 | (meta-Mcont (tail Mcont)) 318 | (operator (if (symbol? proc-name-or-cont) 319 | (cdr (get proc-name-or-cont meta-env)) 320 | proc-name-or-cont))) 321 | (cond ((procedure? operator) 322 | (if (pair? (member operator primitive-procedures)) 323 | ((meta-apply 'base-apply operator operand meta-env meta-cont) 324 | meta-Mcont) 325 | ((scheme-apply operator operand) ; evaluator functions 326 | Mcont))) 327 | (else 328 | ((meta-apply 'base-apply operator operand meta-env meta-cont) 329 | meta-Mcont)))))) 330 | ; 331 | ; Initial Continuation 332 | ; 333 | (define (init-cont env level turn cont) 334 | (meta-apply cont 335 | (lambda (answer) 336 | (write level) (write '-) (write turn) (display ": ") 337 | (primitive-write answer) 338 | (newline) 339 | (write level) (write '-) (write (+ turn 1)) (display "> ") 340 | (meta-apply 'base-eval (read) env 341 | (lambda (ans) 342 | (meta-apply 'init-cont env level (+ turn 1) 343 | (lambda (cont) (meta-apply cont ans)))))))) 344 | 345 | (define (run env level answer) 346 | (meta-apply 'init-cont env level 0 347 | (lambda (cont) (meta-apply cont answer)))) 348 | ; 349 | ; Environment 350 | ; 351 | ;(load "env.scm") 352 | ; 353 | ; Primitive Procedures 354 | ; 355 | (define primitive-procedures 356 | (list car cdr cons list pair? null? eq? eqv? equal? not set-car! set-cdr! 357 | append 358 | primitive-write primitive-pp primitive-display newline primitive-format read 359 | primitive-print primitive-procedure? 360 | + - * / = < > quotient remainder number? 361 | boolean? string? symbol? assq member length force 362 | open-input-file close-input-port eof-object? 363 | map scheme-apply 364 | make-pairs extend can-receive? get set-value! define-value 365 | search copy 366 | )) 367 | ; 368 | ; Initial Environment 369 | ; 370 | (define init-env (list (list 371 | (cons 'car car) 372 | (cons 'cdr cdr) 373 | (cons 'cons cons) 374 | (cons 'list list) 375 | (cons 'pair? pair?) 376 | (cons 'null? null?) 377 | (cons 'eq? eq?) 378 | (cons 'eqv? eqv?) 379 | (cons 'equal? equal?) 380 | (cons 'not not) 381 | (cons 'set-car! set-car!) 382 | (cons 'set-cdr! set-cdr!) 383 | (cons 'append append) 384 | (cons 'write primitive-write) 385 | (cons 'pp primitive-pp) 386 | (cons 'display primitive-display) 387 | (cons 'print primitive-print) 388 | (cons 'newline newline) 389 | (cons 'format primitive-format) 390 | (cons 'read read) 391 | (cons '+ +) 392 | (cons '- -) 393 | (cons '* *) 394 | (cons '/ /) 395 | (cons '= =) 396 | (cons '> >) 397 | (cons '< <) 398 | (cons 'quotient quotient) 399 | (cons 'remainder remainder) 400 | (cons 'number? number?) 401 | (cons 'boolean? boolean?) 402 | (cons 'string? string?) 403 | (cons 'symbol? symbol?) 404 | (cons 'procedure? primitive-procedure?) 405 | (cons 'assq assq) 406 | (cons 'member member) 407 | (cons 'length length) 408 | (cons 'force force) 409 | (cons 'open-input-file open-input-file) 410 | (cons 'close-input-port close-input-port) 411 | (cons 'eof-object? eof-object?) 412 | 413 | (cons 'map map) 414 | (cons 'scheme-apply scheme-apply) 415 | 416 | (cons 'empty-env empty-env) 417 | (cons 'make-pairs make-pairs) 418 | (cons 'extend extend) 419 | (cons 'can-receive? can-receive?) 420 | (cons 'get get) 421 | (cons 'set-value! set-value!) 422 | (cons 'define-value define-value) 423 | (cons 'search search) 424 | (cons 'copy copy) 425 | (cons 'get-global-env get-global-env) 426 | 427 | (cons 'base-eval base-eval) 428 | (cons 'eval-application eval-application) 429 | (cons 'eval-var eval-var) 430 | (cons 'eval-quote eval-quote) 431 | (cons 'eval-if eval-if) 432 | (cons 'eval-cond eval-cond) 433 | (cons 'eval-define eval-define) 434 | (cons 'eval-set! eval-set!) 435 | (cons 'lambda-tag lambda-tag) 436 | (cons 'eval-lambda eval-lambda) 437 | (cons 'eval-begin eval-begin) 438 | (cons 'eval-let eval-let) 439 | (cons 'eval-let* eval-let*) 440 | (cons 'eval-letrec eval-letrec) 441 | (cons 'eval-EM eval-EM) 442 | (cons 'eval-primitive-EM eval-primitive-EM) 443 | (cons 'eval-exit eval-exit) 444 | (cons 'eval-list eval-list) 445 | (cons 'base-apply base-apply) 446 | (cons 'my-error my-error) 447 | (cons 'eval-load eval-load) 448 | (cons 'eval-and eval-and) 449 | (cons 'eval-or eval-or) 450 | (cons 'delay-tag delay-tag) 451 | (cons 'eval-delay eval-delay) 452 | (cons 'eval-cons-stream eval-cons-stream) 453 | (cons 'eval-map eval-map) 454 | 455 | (cons 'init-env 0) ; to be filled when making a new level 456 | (cons 'init-cont init-cont) 457 | (cons 'run run) 458 | (cons 'primitive-procedures primitive-procedures) 459 | (cons 'old-env old-env) 460 | (cons 'old-cont old-cont) 461 | ))) 462 | ; 463 | ; Meta-level Initial Continuation 464 | ; 465 | (define (meta-init-cont env level supplied-env) 466 | (define-value 'init-env supplied-env env) ; share-env 467 | (display "New level loaded.") (newline) 468 | (lambda (result) 469 | (meta-apply 'run env level result))) 470 | ; 471 | ; Initial Meta-Continuation 472 | ; 473 | (define (init-Mcont level supplied-env) 474 | (let ((env (copy init-env))) 475 | (cons-stream (list env (meta-init-cont env level supplied-env)) 476 | (init-Mcont (+ level 1) env)))) 477 | ; 478 | ; Start up 479 | ; 480 | (define (black) 481 | (let* ((base-Mcont (init-Mcont 0 (copy init-env))) 482 | (env (car (head base-Mcont))) 483 | (cont (car (cdr (head base-Mcont)))) 484 | (Mcont (tail base-Mcont))) 485 | ((cont 'start) Mcont))) 486 | -------------------------------------------------------------------------------- /break.blk: -------------------------------------------------------------------------------- 1 | (define (loop prompt env ans) 2 | (write ans)(newline) 3 | (display prompt)(display "> ") 4 | (base-eval (read) env (lambda (ans) (loop prompt env ans)))) 5 | 6 | (define (eval-break pred env cont) 7 | (define (run-break-loop) 8 | (let ((result (loop "break" env 'break-loop))) 9 | (write 'break-end)(newline) 10 | (cont result))) 11 | (if (null? pred) 12 | (run-break-loop) 13 | (base-eval (car pred) env 14 | (lambda (pred) (if pred (run-break-loop) 15 | (cont #f)))))) 16 | 17 | (define (eval-inspect closure env cont) 18 | (base-eval closure env (lambda (closure) 19 | (let ((lambda-env (car (cdr (cdr (cdr closure)))))) 20 | (let ((result (loop "inspect" lambda-env 'inspect-loop))) 21 | (write 'inspect-end)(newline) 22 | (cont result)))))) 23 | 24 | (let ((original-eval-application eval-application)) 25 | (set! eval-application 26 | (lambda (exp env cont) 27 | (cond ((eq? (car exp) 'break) 28 | (eval-break (cdr exp) env cont)) 29 | ((eq? (car exp) 'inspect) 30 | (eval-inspect (car (cdr exp)) env cont)) 31 | (else 32 | (original-eval-application exp env cont)))))) 33 | -------------------------------------------------------------------------------- /compare: -------------------------------------------------------------------------------- 1 | # 2 | sed -e "s/meta-apply '//g" -e "s/meta-apply //g" black.scm > __tmp__ 3 | diff __tmp__ int.scm | less 4 | rm __tmp__ 5 | -------------------------------------------------------------------------------- /env.scm: -------------------------------------------------------------------------------- 1 | ; 2 | ; Environment 3 | ; 4 | (define empty-env '(())) 5 | (define (make-pairs params args) 6 | (cond ((null? params) '()) 7 | ((symbol? params) (list (cons params args))) 8 | (else 9 | (cons (cons (car params) (car args)) 10 | (make-pairs (cdr params) (cdr args)))))) 11 | (define (extend env params args) 12 | (cons (make-pairs params args) env)) 13 | (define (can-receive? params args) 14 | (cond ((null? params) (null? args)) 15 | ((not (pair? params)) #t) 16 | ((pair? args) (can-receive? (cdr params) (cdr args))) 17 | (else #f))) 18 | (define (get var env) 19 | (if (null? env) 20 | '() 21 | (let ((pair (assq var (car env)))) 22 | (if (pair? pair) 23 | pair 24 | (get var (cdr env)))))) 25 | (define (set-value! var value env) 26 | (let ((pair (get var env))) 27 | (if (pair? pair) 28 | (set-cdr! pair value) 29 | (error 'set-value!: var 'is 'unbound)))) 30 | (define (define-value var value env) 31 | (let ((pair (assq var (car env)))) 32 | (if (pair? pair) 33 | (set-cdr! pair value) 34 | (set-car! env (cons (cons var value) (car env)))))) 35 | (define (search value env) 36 | (define (reverse-assq value env) 37 | (cond ((null? env) '()) 38 | ((eq? value (cdr (car env))) (car env)) 39 | (else (reverse-assq value (cdr env))))) 40 | (if (null? env) 41 | '() 42 | (let ((pair (reverse-assq value (car env)))) 43 | (if (pair? pair) 44 | pair 45 | (search value (cdr env)))))) 46 | (define (copy env) 47 | (define (copy-local env) 48 | (if (null? env) 49 | '() 50 | (cons (cons (car (car env)) 51 | (cdr (car env))) 52 | (copy-local (cdr env))))) 53 | (if (null? env) 54 | '() 55 | (cons (copy-local (car env)) 56 | (copy (cdr env))))) 57 | (define (get-global-env env) 58 | (define (get-global-env-local env) 59 | (if (null? (cdr env)) 60 | env 61 | (get-global-env-local (cdr env)))) 62 | (if (null? env) 63 | env 64 | (get-global-env-local env))) 65 | -------------------------------------------------------------------------------- /examples/church.scm: -------------------------------------------------------------------------------- 1 | ;; Church Booleans 2 | (define tru 3 | (lambda (t) (lambda (f) t))) 4 | 5 | (define fls 6 | (lambda (t) (lambda (f) f))) 7 | 8 | (define to_bool 9 | (lambda (b) (b #t #f))) 10 | 11 | ;; Pairs 12 | (define pair 13 | (lambda (f) (lambda (s) (lambda (b) ((b f) s))))) 14 | 15 | (define fst 16 | (lambda (p) (p tru))) 17 | 18 | (define snd 19 | (lambda (p) (p fls))) 20 | 21 | (define to_tuple 22 | (lambda (p) (cons (fst p) (snd p)))) 23 | 24 | (define c0 25 | (lambda (s) (lambda (z) z))) 26 | 27 | (define c1 28 | (lambda (s) (lambda (z) (s z)))) 29 | 30 | (define c2 31 | (lambda (s) (lambda (z) (s (s z))))) 32 | 33 | (define scc 34 | (lambda (n) (lambda (s) (lambda (z) (s ((n s) z)))))) 35 | 36 | (define to_int 37 | (lambda (n) ((n (lambda (v) (+ v 1))) 0))) 38 | 39 | (define iszro 40 | (lambda (n) ((n (lambda (x) fls)) tru))) 41 | 42 | (define plus 43 | (lambda (m) (lambda (n) (lambda (s) (lambda (z) ((m s) ((n s) z))))))) 44 | 45 | (define zz 46 | ((pair c0) c0)) 47 | 48 | (define ss 49 | (lambda (p) ((pair (snd p)) ((plus c1) (snd p))))) 50 | 51 | (define prd 52 | (lambda (n) (fst ((n ss) zz)))) 53 | 54 | (define prd-alt 55 | (lambda (n) (lambda (s) (lambda (z) (((n (lambda (g) (lambda (h) (h (g s))))) (lambda (u) z)) (lambda (u) u)))))) 56 | -------------------------------------------------------------------------------- /examples/cnv.scm: -------------------------------------------------------------------------------- 1 | (define zip 2 | (lambda (xs ys) 3 | (cond 4 | ((or (null? xs) (null? ys)) 5 | '()) 6 | (else 7 | (cons 8 | (cons (car xs) (car ys)) 9 | (zip (cdr xs) (cdr ys))))))) 10 | 11 | (define cnv2 12 | (lambda (xs ys) 13 | (define walk 14 | (lambda (xs k) 15 | (cond 16 | ((null? xs) 17 | (k '() ys)) 18 | (else 19 | (walk (cdr xs) 20 | (lambda (r ys) (k (cons (cons (car xs) (car ys)) r) 21 | (cdr ys)))))))) 22 | (walk xs (lambda (r ys) r)))) 23 | 24 | (define cnv3 25 | (lambda (xs ys) 26 | (define walk 27 | (lambda (xs) 28 | (cond 29 | ((null? xs) 30 | (cons '() ys)) 31 | (else 32 | (let ((rys (walk (cdr xs)))) 33 | (let ((r (car rys)) 34 | (ys (cdr rys))) 35 | (cons (cons (cons (car xs) (car ys)) r) 36 | (cdr ys)))))))) 37 | (car (walk xs)))) 38 | 39 | #; 40 | (begin 41 | (zip '(1 2 3) '(a b c)) 42 | (cnv2 '(1 2 3) '(a b c)) 43 | (cnv3 '(1 2 3) '(a b c)) 44 | ) 45 | -------------------------------------------------------------------------------- /examples/instr.blk: -------------------------------------------------------------------------------- 1 | (define eval-instr 2 | (lambda (exp env cont) 3 | (let ((original-eval-application eval-application) 4 | (instr-counter 0)) 5 | (set! eval-application 6 | (lambda (exp env cont) 7 | (set! instr-counter (+ instr-counter 1)) 8 | (original-eval-application exp env cont))) 9 | (base-eval exp env (lambda (ans) 10 | (set! eval-application original-eval-application) 11 | (display "#app: ") (write instr-counter) (newline) 12 | (cont ans)))))) 13 | 14 | (let ((original-eval-application eval-application)) 15 | (set! eval-application 16 | (lambda (exp env cont) 17 | (cond ((eq? (car exp) 'instr) 18 | (eval-instr (car (cdr exp)) env cont)) 19 | (else 20 | (original-eval-application exp env cont)))))) 21 | -------------------------------------------------------------------------------- /examples/instr2.blk: -------------------------------------------------------------------------------- 1 | (define eval-instr 2 | (lambda (exp env cont) 3 | (let ((restore-thunks '()) 4 | (total-counter 0) 5 | (display-msg (lambda (msg counter) 6 | (display "#") (display msg) (display ": ") 7 | (display counter) (newline)))) 8 | (let ((add-instr! 9 | (lambda (msg original set-original!) 10 | (let ((counter 0)) 11 | (set! restore-thunks 12 | (cons (lambda () 13 | (set! total-counter (+ total-counter counter)) 14 | (set-original! original) 15 | (display-msg msg counter)) 16 | restore-thunks)) 17 | (set-original! (lambda (exp env cont) 18 | (set! counter (+ counter 1)) 19 | (original exp env cont))))))) 20 | (add-instr! 'app eval-application (lambda (v) (set! eval-application v))) 21 | (add-instr! 'lam eval-lambda (lambda (v) (set! eval-lambda v))) 22 | (add-instr! 'var eval-var (lambda (v) (set! eval-var v)))) 23 | (base-eval exp env (lambda (ans) 24 | (newline) 25 | (map (lambda (t) (t)) restore-thunks) 26 | (display-msg 'total total-counter) 27 | (cont ans)))))) 28 | 29 | (let ((original-eval-application eval-application)) 30 | (set! eval-application 31 | (lambda (exp env cont) 32 | (cond ((eq? (car exp) 'instr) 33 | (eval-instr (car (cdr exp)) env cont)) 34 | (else 35 | (original-eval-application exp env cont)))))) 36 | -------------------------------------------------------------------------------- /examples/pal.scm: -------------------------------------------------------------------------------- 1 | (define pal_c 2 | (lambda (xs) 3 | (define walk 4 | (lambda (xs1 xs2 k) 5 | (cond 6 | ((and (null? xs2)) 7 | (k xs1)) 8 | ((null? (cdr xs2)) 9 | (k (cdr xs1))) 10 | (else 11 | (walk 12 | (cdr xs1) (cdr (cdr xs2)) 13 | (lambda (ys) 14 | (and (equal? (car xs1) (car ys)) 15 | (k (cdr ys))))))))) 16 | (walk xs xs (lambda (v) #t)))) 17 | 18 | #; 19 | (begin 20 | (pal_c '()) 21 | (pal_c '(1)) 22 | (pal_c '(1 2)) 23 | (pal_c '(1 2 2 1)) 24 | (pal_c '(1 2 1)) 25 | (pal_c '(1 2 3 1)) 26 | ) 27 | -------------------------------------------------------------------------------- /examples/stack.scm: -------------------------------------------------------------------------------- 1 | ;; works in MIT Scheme 2 | ;; need (load-option 'format) 3 | 4 | (define print-stack 5 | (lambda (es) 6 | (let ((m "~26A~26A~%")) 7 | (map ;; for-each 8 | (lambda (e) 9 | (let ((n (car e)) 10 | (down (car (cdr e))) 11 | (up (car (cdr (cdr e))))) 12 | 13 | (format #t m (cons n down) up) 14 | (format #t m "|" "^") 15 | (format #t m "V" "|"))) 16 | es) 17 | 18 | (format #t "---------------------------~%")))) 19 | 20 | -------------------------------------------------------------------------------- /examples/start.scm: -------------------------------------------------------------------------------- 1 | (load "env.scm") 2 | (load "stream.scm") 3 | (define scheme-apply apply) 4 | (load "black.scm") 5 | (black) 6 | -------------------------------------------------------------------------------- /examples/taba.blk: -------------------------------------------------------------------------------- 1 | (define eval-taba-call 2 | (lambda (original-eval-application) 3 | (lambda (exp env cont) 4 | (write 'taba-push:) 5 | (eval-list 6 | (cdr exp) env 7 | (lambda (ans-args) 8 | (write (cons (car exp) ans-args)) 9 | (newline) 10 | (original-eval-application 11 | exp env 12 | (lambda (ans) 13 | (write 'taba-pop:) 14 | (write ans) 15 | (newline) 16 | (cont ans)))))))) 17 | 18 | (define eval-taba 19 | (lambda (fns) 20 | (lambda (exp env cont) 21 | (let ((original-eval-application eval-application)) 22 | (map (lambda (fn) 23 | (add-app-hook! 24 | fn 25 | (eval-taba-call eval-application))) 26 | fns) 27 | (base-eval 28 | exp env 29 | (lambda (ans) 30 | (set! eval-application original-eval-application) 31 | (cont ans))))))) 32 | 33 | (add-app-hook! 34 | 'taba 35 | (lambda (exp env cont) 36 | ((eval-taba (car (cdr exp))) (car (cdr (cdr exp))) env cont))) 37 | -------------------------------------------------------------------------------- /examples/taba2.blk: -------------------------------------------------------------------------------- 1 | (define eval-taba-call 2 | (lambda (add! original-eval-application) 3 | (lambda (exp env cont) 4 | (eval-list 5 | (cdr exp) env 6 | (lambda (ans-args) 7 | (original-eval-application 8 | exp env 9 | (lambda (ans) 10 | (add! ans-args ans) 11 | (cont ans)))))))) 12 | 13 | (define eval-taba 14 | (lambda (fns) 15 | (lambda (exp env cont) 16 | (let ((original-eval-application eval-application) 17 | (stack '())) 18 | (map (lambda (fn) 19 | (add-app-hook! 20 | fn 21 | (eval-taba-call 22 | (lambda (ans-args ans) 23 | (set! stack (cons (list fn ans-args ans) stack))) 24 | eval-application))) 25 | fns) 26 | (base-eval 27 | exp env 28 | (lambda (ans) 29 | (set! eval-application original-eval-application) 30 | (cont 31 | (list ans stack)))))))) 32 | 33 | (add-app-hook! 34 | 'taba 35 | (lambda (exp env cont) 36 | ((eval-taba (car (cdr exp))) (car (cdr (cdr exp))) env cont))) 37 | -------------------------------------------------------------------------------- /examples/taba3.blk: -------------------------------------------------------------------------------- 1 | (define eval-taba-call 2 | (lambda (add! original-eval-application) 3 | (lambda (exp env cont) 4 | (eval-list 5 | (cdr exp) env 6 | (lambda (ans-args) 7 | (original-eval-application 8 | exp env 9 | (lambda (ans) 10 | (add! ans-args ans) 11 | (cont ans)))))))) 12 | 13 | (define eval-taba 14 | (lambda (fns) 15 | (lambda (exp env cont) 16 | (let ((original-eval-application eval-application) 17 | (stack '())) 18 | (map (lambda (fn) 19 | (add-app-hook! 20 | fn 21 | (eval-taba-call 22 | (lambda (ans-args ans) 23 | (set! stack (cons (list fn ans-args ans) stack))) 24 | eval-application))) 25 | fns) 26 | (base-eval 27 | exp env 28 | (lambda (ans) 29 | (set! eval-application original-eval-application) 30 | (print-stack stack) 31 | (cont ans))))))) 32 | 33 | (add-app-hook! 34 | 'taba 35 | (lambda (exp env cont) 36 | ((eval-taba (car (cdr exp))) (car (cdr (cdr exp))) env cont))) 37 | -------------------------------------------------------------------------------- /examples/transcript.scm: -------------------------------------------------------------------------------- 1 | ;; for MIT Scheme: 2 | (load-option 'format) 3 | 4 | ;; start running from the parent directory 5 | (load "env.scm") 6 | (load "stream.scm") 7 | (define scheme-apply apply) 8 | (load "black.scm") 9 | (black) 10 | 11 | (exec-at-metalevel 12 | (let ((old-eval base-eval)) 13 | (set! base-eval (lambda (exp env cont) 14 | (write 'trace:) (write exp) (newline) 15 | (old-eval exp env cont))))) 16 | 17 | (car (cons 1 2)) 18 | 19 | (exit 'bye) 20 | 21 | (exec-at-metalevel 22 | (load "break.blk")) 23 | 24 | (inspect base-eval) ;; works in Chez but not MIT or Chicken Scheme 25 | base-eval 26 | (exit 'good-bye) 27 | (old-cont 'hello) 28 | (+ 1 2) 29 | 30 | ;; resume with a different function at the lower level 31 | (define inc (lambda (x) (+ x 1))) 32 | (incr 2) ;; typo 33 | (base-eval 'inc old-env (lambda (x) x)) ;; see what inc is 34 | (base-eval 'inc old-env old-cont) ;; resume with inc for incr 35 | 36 | (load "examples/start.scm") 37 | 38 | ;; instrumentation 39 | (exec-at-metalevel 40 | (load "examples/instr.blk")) 41 | ;; or 42 | (exec-at-metalevel 43 | (load "examples/instr2.blk")) 44 | 45 | ;; Church Encoding 46 | ;; http://en.wikipedia.org/wiki/Church_encoding 47 | ;; Types and Programming Languages: section 5.2, Programming in the Lambda-Calculus 48 | (load "examples/church.scm") 49 | (instr (prd c2)) 50 | (instr (prd-alt c2)) 51 | (instr (to_int (prd-alt c2))) 52 | (instr (to_int (prd c2))) 53 | 54 | (load "examples/start.scm") 55 | (EM (load "examples/utils.blk")) 56 | ;; TABA: There And Back Again 57 | ;; http://www.brics.dk/RS/02/12/BRICS-RS-02-12.pdf (ICFP pearl) 58 | ;; http://brics.dk/RS/05/3/BRICS-RS-05-3.pdf (extended journal version) 59 | 60 | (EM (load "examples/taba.blk")) 61 | ;; or 62 | (EM (load "examples/taba2.blk")) 63 | ;; or 64 | (EM (load "examples/stack.scm")) 65 | (EM (load "examples/taba3.blk")) 66 | 67 | (load "examples/cnv.scm") 68 | (taba (cnv3 walk) (cnv3 '(1 2 3) '(a b c))) 69 | 70 | (load "examples/pal.scm") 71 | (taba (pal_c walk) (pal_c '(1 2 2 1))) 72 | -------------------------------------------------------------------------------- /examples/utils.blk: -------------------------------------------------------------------------------- 1 | (define add-app-hook! 2 | (lambda (n ev) 3 | (let ((original-eval-application eval-application)) 4 | (set! eval-application 5 | (lambda (exp env cont) 6 | (cond ((eq? (car exp) n) 7 | (ev exp env cont)) 8 | (else 9 | (original-eval-application exp env cont)))))))) 10 | -------------------------------------------------------------------------------- /init.scm: -------------------------------------------------------------------------------- 1 | (load "env.scm") 2 | (load "stream.scm") 3 | (define scheme-apply apply) 4 | (load "black.scm") 5 | (black) 6 | -------------------------------------------------------------------------------- /int.scm: -------------------------------------------------------------------------------- 1 | ; 2 | ; Eval functions 3 | ; 4 | (define (base-eval exp env cont) 5 | (cond ((number? exp) (cont exp)) 6 | ((boolean? exp) (cont exp)) 7 | ((string? exp) (cont exp)) 8 | ((symbol? exp) (eval-var exp env cont)) 9 | ((eq? (car exp) 'quote) (eval-quote exp env cont)) 10 | ((eq? (car exp) 'if) (eval-if exp env cont)) 11 | ((eq? (car exp) 'cond) (eval-cond (cdr exp) env cont)) 12 | ((eq? (car exp) 'define) (eval-define exp env cont)) 13 | ((eq? (car exp) 'set!) (eval-set! exp env cont)) 14 | ((eq? (car exp) 'lambda) (eval-lambda exp env cont)) 15 | ((eq? (car exp) 'begin) (eval-begin (cdr exp) env cont)) 16 | ((eq? (car exp) 'let) (eval-let 17 | (car (cdr exp)) (cdr (cdr exp)) env cont)) 18 | ((eq? (car exp) 'let*) (eval-let* 19 | (car (cdr exp)) (cdr (cdr exp)) env cont)) 20 | ((eq? (car exp) 'letrec) (eval-letrec 21 | (car (cdr exp)) (cdr (cdr exp)) env cont)) 22 | ((eq? (car exp) 'EM) (eval-EM exp env cont)) 23 | ((eq? (car exp) 'exec-at-metalevel) 24 | (eval-EM exp env cont)) 25 | ((eq? (car exp) 'primitive-EM) 26 | (eval-primitive-EM exp env cont)) 27 | ((eq? (car exp) 'exit) (eval-exit exp env cont)) 28 | ((eq? (car exp) 'load) (eval-load exp env cont)) 29 | ((eq? (car exp) 'and) (eval-and (cdr exp) env cont)) 30 | ((eq? (car exp) 'or) (eval-or (cdr exp) env cont)) 31 | ((eq? (car exp) 'delay) (eval-delay exp env cont)) 32 | ((eq? (car exp) 'cons-stream) 33 | (eval-cons-stream exp env cont)) 34 | (else (eval-application exp env cont)))) 35 | (define (eval-application exp env cont) 36 | (eval-list exp env 37 | (lambda (l) (base-apply (car l) (cdr l) env cont)))) 38 | (define (eval-var exp env cont) 39 | (let ((pair (get exp env))) 40 | (if (pair? pair) 41 | (cont (cdr pair)) 42 | (my-error 43 | (list 'eval-var: 'unbound 'variable: exp) env cont)))) 44 | (define (eval-quote exp env cont) (cont (car (cdr exp)))) 45 | (define (eval-if exp env cont) 46 | (let ((pred-part (car (cdr exp))) 47 | (then-part (car (cdr (cdr exp)))) 48 | (else-part (cdr (cdr (cdr exp))))) 49 | (base-eval pred-part env (lambda (p) 50 | (cond (p (base-eval then-part env cont)) 51 | ((null? else-part) (cont #f)) 52 | (else 53 | (base-eval (car else-part) env cont))))))) 54 | (define (eval-cond clauses env cont) 55 | (cond ((null? clauses) (cont '())) 56 | ((eq? (car (car clauses)) 'else) 57 | (eval-begin (cdr (car clauses)) env cont)) 58 | (else 59 | (base-eval 60 | (car (car clauses)) 61 | env 62 | (lambda (pred) 63 | (if pred 64 | (eval-begin (cdr (car clauses)) 65 | env cont) 66 | (eval-cond (cdr clauses) 67 | env cont))))))) 68 | (define (eval-define exp env cont) 69 | (if (pair? (car (cdr exp))) 70 | (let ((var (car (car (cdr exp)))) 71 | (body (cons 'lambda 72 | (cons (cdr (car (cdr exp))) 73 | (cdr (cdr exp)))))) 74 | (base-eval body env 75 | (lambda (data) 76 | (define-value var data env) 77 | (cont var)))) 78 | (let ((var (car (cdr exp))) 79 | (body (car (cdr (cdr exp))))) 80 | (base-eval body env 81 | (lambda (data) 82 | (define-value var data env) 83 | (cont var)))))) 84 | (define (eval-set! exp env cont) 85 | (let ((var (car (cdr exp))) 86 | (body (car (cdr (cdr exp))))) 87 | (base-eval body env 88 | (lambda (data) 89 | (let ((pair (get var env))) 90 | (if (pair? pair) 91 | (begin (set-value! var data env) 92 | (cont var)) 93 | (my-error 94 | (list 'eval-set!: 'unbound 'variable var) 95 | env cont))))))) 96 | (define lambda-tag (cons 'lambda 'tag)) 97 | (define (eval-lambda exp env cont) 98 | (let ((lambda-body (cdr (cdr exp))) 99 | (lambda-params (car (cdr exp)))) 100 | (cont (list lambda-tag lambda-params lambda-body env)))) 101 | (define (eval-begin body env cont) 102 | (define (eval-begin-local body) 103 | (if (null? (cdr body)) 104 | (base-eval (car body) env cont) 105 | (base-eval (car body) env 106 | (lambda (x) (eval-begin-local (cdr body)))))) 107 | (if (null? body) 108 | (my-error '(eval-begin: null body) env cont) 109 | (eval-begin-local body))) 110 | (define (eval-let pairs body env cont) 111 | (let ((params (map car pairs)) 112 | (args (map (lambda (x) (car (cdr x))) pairs))) 113 | (eval-list args env 114 | (lambda (operand) 115 | (eval-begin body 116 | (extend env params operand) 117 | cont))))) 118 | (define (eval-let* pairs body env cont) 119 | (if (null? pairs) 120 | (eval-begin body env cont) 121 | (base-eval (car (cdr (car pairs))) env (lambda (arg) 122 | (eval-let* (cdr pairs) body 123 | (extend env (list (car (car pairs))) (list arg)) 124 | cont))))) 125 | (define (eval-letrec pairs body env cont) 126 | (define (set-value-list! params operand env) 127 | (if (null? params) 128 | #f 129 | (begin (set-value! (car params) (car operand) env) 130 | (set-value-list! (cdr params) (cdr operand) env)))) 131 | (let ((params (map car pairs)) 132 | (args (map (lambda (x) (car (cdr x))) pairs))) 133 | (let ((letrec-env (extend env params params))) 134 | (eval-list args letrec-env 135 | (lambda (operand) 136 | (set-value-list! params operand letrec-env) 137 | (eval-begin body letrec-env cont)))))) 138 | (define (eval-EM exp env cont) 139 | (cont (primitive-EM (car (cdr exp))))) 140 | (define (eval-primitive-EM exp env cont) 141 | (base-eval (car (cdr exp)) env 142 | (lambda (body) (cont (primitive-EM body))))) 143 | (define (eval-exit exp env cont) 144 | (base-eval (car (cdr exp)) env 145 | (lambda (x) (my-error x env cont)))) 146 | (define (eval-list exp env cont) 147 | (if (null? exp) 148 | (cont '()) 149 | (base-eval (car exp) env 150 | (lambda (val1) 151 | (eval-list (cdr exp) env 152 | (lambda (val2) 153 | (cont (cons val1 val2)))))))) 154 | (define (base-apply operator operand env cont) 155 | (cond ((procedure? operator) 156 | (cond ((eq? operator map) 157 | (eval-map 158 | (car operand) (car (cdr operand)) env cont)) 159 | ((eq? operator scheme-apply) 160 | (base-apply 161 | (car operand) (car (cdr operand)) env cont)) 162 | ((eq? operator force) 163 | (let ((arg (car operand))) 164 | (if (and (pair? arg) 165 | (eq? (car arg) delay-tag)) 166 | (let ((promise-body (car (cdr arg))) 167 | (promise-env (car (cdr (cdr arg)))) 168 | (pair (cdr (cdr arg)))) 169 | (if (pair? (cdr pair)) 170 | (cont (car (cdr pair))) 171 | (base-eval promise-body promise-env 172 | (lambda (ans) 173 | (set-cdr! pair (list ans)) 174 | (cont ans))))) 175 | (cont arg)))) 176 | ((pair? (member operator primitive-procedures)) 177 | (cont (scheme-apply operator operand))) 178 | (else ; called when going down a level. 179 | (cont (scheme-apply operator operand))))) 180 | ((and (pair? operator) 181 | (eq? (car operator) lambda-tag)) 182 | (let ((lambda-params (car (cdr operator))) 183 | (lambda-body (car (cdr (cdr operator)))) 184 | (lambda-env (car (cdr (cdr (cdr operator)))))) 185 | (if (can-receive? lambda-params operand) 186 | (eval-begin 187 | lambda-body 188 | (extend lambda-env lambda-params operand) 189 | cont) 190 | (my-error 191 | (list 'base-apply: 'Wrong 'number 'of 'arguments: 192 | operand 'to: lambda-params) 193 | env cont)))) 194 | (else 195 | (my-error (list 'Not 'a 'function: operator) env cont)))) 196 | (define old-env 0) 197 | (define old-cont 0) 198 | (define (my-error exp env cont) 199 | (set! old-env env) 200 | (set! old-cont cont) 201 | exp) 202 | (define (eval-load exp env cont) 203 | (define port (open-input-file (car (cdr exp)))) 204 | (define (load-local) 205 | (let ((input (read port))) 206 | (if (eof-object? input) 207 | (begin (close-input-port port) 208 | (cont 'done)) 209 | (base-eval input env 210 | (lambda (value) (load-local)))))) 211 | (load-local)) 212 | (define (eval-and body env cont) 213 | (cond ((null? body) (cont #t)) 214 | ((null? (cdr body)) 215 | (base-eval (car body) env cont)) 216 | (else 217 | (base-eval (car body) env 218 | (lambda (result) 219 | (if result 220 | (eval-and (cdr body) env cont) 221 | (cont result))))))) 222 | (define (eval-or body env cont) 223 | (if (null? body) 224 | (cont #f) 225 | (base-eval (car body) env 226 | (lambda (result) 227 | (if result 228 | (cont result) 229 | (eval-or (cdr body) env cont)))))) 230 | (define delay-tag (cons 'delay 'tag)) 231 | (define (eval-delay exp env cont) 232 | (let ((delay-body (car (cdr exp)))) 233 | (cont (list delay-tag delay-body env)))) 234 | (define (eval-cons-stream exp env cont) 235 | (let ((car-part (car (cdr exp))) 236 | (cdr-part (car (cdr (cdr exp))))) 237 | (base-eval (list 'cons car-part (list 'delay cdr-part)) 238 | env cont))) 239 | 240 | ; 241 | ; Primitives 242 | ; 243 | (define (eval-map fun lst env cont) 244 | (if (null? lst) 245 | (cont '()) 246 | (base-apply fun (list (car lst)) env 247 | (lambda (x) (eval-map fun (cdr lst) env 248 | (lambda (y) (cont (cons x y)))))))) 249 | (define (primitive-procedure? . operand) 250 | (let ((arg (car operand))) 251 | (or (procedure? arg) 252 | (and (pair? arg) 253 | (eq? (car arg) lambda-tag))))) 254 | (define (filter arg) 255 | (if (pair? arg) 256 | (cond ((eq? (car arg) lambda-tag) 257 | (let ((lambda-params (car (cdr arg))) 258 | (lambda-body (car (cdr (cdr arg))))) 259 | (cons 'lambda (cons lambda-params lambda-body)))) 260 | ((eq? (car arg) delay-tag) 261 | (let ((delay-body (car (cdr arg)))) 262 | (list ' delay-body))) 263 | (else 264 | (cons (filter (car arg)) 265 | (filter (cdr arg))))) 266 | arg)) 267 | (define (primitive-display . args) 268 | (display (filter (car args)))) 269 | (define (primitive-write . args) 270 | (write (filter (car args)))) 271 | (define (primitive-pp . args) 272 | (pp (filter (car args)))) 273 | (define (primitive-print lst depth length) 274 | (define (print-sub lst d l top?) 275 | (cond ((pair? lst) 276 | (cond ((= l 0) 277 | (if top? (display "(...)") (display " ...)"))) 278 | ((= d 0) (display "#")) 279 | (else 280 | (if top? (display "(") (display " ")) 281 | (print-sub (car lst) (- d 1) length #t) 282 | (cond ((pair? (cdr lst)) 283 | (print-sub (cdr lst) d (- l 1) #f)) 284 | ((null? (cdr lst)) 285 | (display ")")) 286 | (else 287 | (begin (display " . ") 288 | (print-sub (cdr lst) d (- l 1) #f) 289 | (display ")"))))))) 290 | (else (display lst)))) 291 | (print-sub lst depth length #t)) 292 | ; 293 | ; Initial Continuation 294 | ; 295 | (define (init-cont env level turn cont) 296 | (cont 297 | (lambda (answer) 298 | (write level) (write '-) (write turn) (display ": ") 299 | (primitive-write answer) 300 | (newline) 301 | (write level) (write '-) (write (+ turn 1)) (display "> ") 302 | (base-eval (read) env 303 | (lambda (ans) 304 | (init-cont env level (+ turn 1) 305 | (lambda (cont) (cont ans)))))))) 306 | 307 | (define (run env level answer) 308 | (init-cont env level 0 309 | (lambda (cont) (cont answer)))) 310 | ; 311 | ; Environment 312 | ; 313 | ;(load "env.scm") 314 | ; 315 | ; Primitive Procedures 316 | ; 317 | (define primitive-procedures 318 | (list car cdr cons list pair? null? eq? eqv? equal? not set-car! set-cdr! 319 | append 320 | primitive-write primitive-pp primitive-display newline read 321 | primitive-print primitive-procedure? 322 | + - * / = < > quotient remainder number? 323 | boolean? string? symbol? assq member length force 324 | open-input-file close-input-port eof-object? 325 | map scheme-apply 326 | make-pairs extend can-receive? get set-value! define-value 327 | search copy 328 | )) 329 | ; 330 | ; Initial Environment 331 | ; 332 | (define init-env (list (list 333 | (cons 'car car) 334 | (cons 'cdr cdr) 335 | (cons 'cons cons) 336 | (cons 'list list) 337 | (cons 'pair? pair?) 338 | (cons 'null? null?) 339 | (cons 'eq? eq?) 340 | (cons 'eqv? eqv?) 341 | (cons 'equal? equal?) 342 | (cons 'not not) 343 | (cons 'set-car! set-car!) 344 | (cons 'set-cdr! set-cdr!) 345 | (cons 'append append) 346 | (cons 'write primitive-write) 347 | (cons 'pp primitive-pp) 348 | (cons 'display primitive-display) 349 | (cons 'print primitive-print) 350 | (cons 'newline newline) 351 | (cons 'read read) 352 | (cons '+ +) 353 | (cons '- -) 354 | (cons '* *) 355 | (cons '/ /) 356 | (cons '= =) 357 | (cons '> >) 358 | (cons '< <) 359 | (cons 'quotient quotient) 360 | (cons 'remainder remainder) 361 | (cons 'number? number?) 362 | (cons 'boolean? boolean?) 363 | (cons 'string? string?) 364 | (cons 'symbol? symbol?) 365 | (cons 'procedure? primitive-procedure?) 366 | (cons 'assq assq) 367 | (cons 'member member) 368 | (cons 'length length) 369 | (cons 'force force) 370 | (cons 'open-input-file open-input-file) 371 | (cons 'close-input-port close-input-port) 372 | (cons 'eof-object? eof-object?) 373 | 374 | (cons 'map map) 375 | (cons 'scheme-apply scheme-apply) 376 | 377 | (cons 'empty-env empty-env) 378 | (cons 'make-pairs make-pairs) 379 | (cons 'extend extend) 380 | (cons 'can-receive? can-receive?) 381 | (cons 'get get) 382 | (cons 'set-value! set-value!) 383 | (cons 'define-value define-value) 384 | (cons 'search search) 385 | (cons 'copy copy) 386 | (cons 'get-global-env get-global-env) 387 | 388 | (cons 'base-eval base-eval) 389 | (cons 'eval-application eval-application) 390 | (cons 'eval-var eval-var) 391 | (cons 'eval-quote eval-quote) 392 | (cons 'eval-if eval-if) 393 | (cons 'eval-cond eval-cond) 394 | (cons 'eval-define eval-define) 395 | (cons 'eval-set! eval-set!) 396 | (cons 'lambda-tag lambda-tag) 397 | (cons 'eval-lambda eval-lambda) 398 | (cons 'eval-begin eval-begin) 399 | (cons 'eval-let eval-let) 400 | (cons 'eval-let* eval-let*) 401 | (cons 'eval-letrec eval-letrec) 402 | (cons 'eval-EM eval-EM) 403 | (cons 'eval-primitive-EM eval-primitive-EM) 404 | (cons 'eval-exit eval-exit) 405 | (cons 'eval-list eval-list) 406 | (cons 'base-apply base-apply) 407 | (cons 'my-error my-error) 408 | (cons 'eval-load eval-load) 409 | (cons 'eval-and eval-and) 410 | (cons 'eval-or eval-or) 411 | (cons 'delay-tag delay-tag) 412 | (cons 'eval-delay eval-delay) 413 | (cons 'eval-cons-stream eval-cons-stream) 414 | (cons 'eval-map eval-map) 415 | 416 | (cons 'init-env 0) ; to be filled when making a new level 417 | (cons 'init-cont init-cont) 418 | (cons 'run run) 419 | (cons 'primitive-procedures primitive-procedures) 420 | (cons 'old-env old-env) 421 | (cons 'old-cont old-cont) 422 | ))) 423 | (define-value 'init-env init-env init-env) 424 | -------------------------------------------------------------------------------- /stream.scm: -------------------------------------------------------------------------------- 1 | (define-syntax cons-stream 2 | (syntax-rules () 3 | ((cons-stream a b) 4 | (delay (cons a b))))) 5 | 6 | (define stream-car 7 | (lambda (s) 8 | (car (force s)))) 9 | 10 | (define stream-cdr 11 | (lambda (s) 12 | (cdr (force s)))) 13 | 14 | (define head stream-car) 15 | (define tail stream-cdr) 16 | --------------------------------------------------------------------------------