001: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 002: ;; SICP第2版をベースにしたSchemeで書かれたSchemeインタプリタ 003: ;; 山本修身 (osami@meijo-u.ac.jp) 004: ;; Wed Dec 2 13:51:28 JST 2015 005: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 006: 007: (define apply-in-underlying-scheme apply) 008: 009: (define (myscheme) 010: ;; 評価子の定義 011: (define (eval exp env) 012: (cond ((self-evaluating? exp) exp) 013: ((variable? exp) 014: (lookup-variable-value exp env)) 015: ((quoted? exp) (text-of-quotation exp)) 016: ((assignment? exp) (eval-assignment exp env)) 017: ((definition? exp) (eval-definition exp env)) 018: ((if? exp) (eval-if exp env)) 019: ((lambda? exp) 020: (make-procedure (lambda-parameters exp) 021: (lambda-body exp) 022: env)) 023: ((begin? exp) 024: (eval-sequence (begin-actions exp) env)) 025: ((cond? exp) (eval (cond->if exp) env)) 026: ((let? exp) (eval (let->lambda exp) env)) 027: ((application? exp) 028: (apply (eval (operator exp) env) 029: (list-of-values (operands exp) env))) 030: (else 031: (error "Unknown expression type -- EVAL" exp)))) 032: 033: ;; 関数へ引数を適用する関数 apply の定義 034: (define (apply procedure arguments) 035: (cond ((primitive-procedure? procedure) ; プリミティブ関数の場合 036: (apply-primitive-procedure procedure arguments)) 037: ((compound-procedure? procedure) ; 関数がlambdaで記述されている場合 038: (eval-sequence 039: (procedure-body procedure) 040: (extend-environment 041: (procedure-parameters procedure) 042: arguments 043: (procedure-environment procedure)))) 044: (else 045: (error 046: "Unknown procedure type -- APPLY" procedure)))) 047: 048: ;; 式のリストのそれぞれの要素を評価してリストにする 049: (define (list-of-values exps env) 050: (if (no-operand? exps) '() 051: (cons (eval (first-operand exps) env) 052: (list-of-values (rest-operands exps) env)))) 053: 054: ;; if文の処理 055: (define (eval-if exp env) 056: (if (true? (eval (if-predicate exp) env)) 057: (eval (if-consequent exp) env) 058: (eval (if-alternative exp) env))) 059: 060: ;; 式のリストを順に評価して最後の式の値を返す 061: (define (eval-sequence exps env) 062: (cond ((last-exp? exps)(eval (first-exp exps) env)) 063: (else (eval (first-exp exps) env) 064: (eval-sequence (rest-exps exps) env)))) 065: 066: ;; set! による代入を評価する 067: (define (eval-assignment exp env) 068: (set-variable-value! (assignment-variable exp) 069: (eval (assignment-value exp) env) 070: env) 071: 'ok) 072: 073: ;; define による変数の定義を実行する. 074: (define (eval-definition exp env) 075: (define-variable! (definition-variable exp) 076: (eval (definition-value exp) env) 077: env) 078: (list 'ok ': (definition-variable exp) 'is 'defined)) 079: 080: ;; 数や文字列など評価時にそのまま返すものかどうかを判定 081: (define (self-evaluating? exp) 082: (cond ((number? exp) #t) 083: ((string? exp) #t) 084: ((eq? exp #t) #t) 085: ((eq? exp #f) #t) 086: (else #f))) 087: 088: ;; 変数であるか否かを判定 089: (define (variable? exp) (symbol? exp)) 090: 091: ;; quoteがついているかどうかを判定.またquoteの本体を取り出す 092: (define (quoted? exp) (tagged-list? exp 'quote)) 093: (define (text-of-quotation exp) (cadr exp)) 094: 095: ;; ('mytag (...)) のような形になってるかを判定する.tagを指定する 096: (define (tagged-list? exp tag) 097: (if (pair? exp) 098: (eq? (car exp) tag) 099: #f)) 100: 101: ;; exp が代入式 (set! .. )であるか判定.また代入の変数と式を取り出す. 102: (define (assignment? exp) 103: (tagged-list? exp 'set!)) 104: (define (assignment-variable exp) (cadr exp)) 105: (define (assignment-value exp) (caddr exp)) 106: 107: ;; 定義式 (define ... )であるか否かを判定.また,定義変数,定義の値を 108: ;; 取り出す.ただし, (define (foo ... ) ) の形のものは 109: ;; (lambda (...) ...)という式にする. 110: (define (definition? exp) 111: (tagged-list? exp 'define)) 112: (define (definition-variable exp) 113: (if (symbol? (cadr exp)) 114: (cadr exp) 115: (caadr exp))) 116: (define (definition-value exp) 117: (if (symbol? (cadr exp)) 118: (caddr exp) 119: (make-lambda (cdadr exp) 120: (cddr exp)))) 121: 122: ;; lambda式であるか否かを判定する.また,lambdaの変数や本体を取り出す 123: (define (lambda? exp) (tagged-list? exp 'lambda)) 124: (define (lambda-parameters exp) (cadr exp)) 125: (define (lambda-body exp) (cddr exp)) 126: 127: ;; lambda式を作る 128: (define (make-lambda parameters body) 129: (cons 'lambda (cons parameters body))) 130: 131: ;; if式であるかどうか判定する.またifの条件,真,偽の場合に評価する 132: ;; 式をそれぞれ取り出す.(if (...) exp) という形にも対応している. 133: (define (if? exp) (tagged-list? exp 'if)) 134: (define (if-predicate exp) (cadr exp)) 135: (define (if-consequent exp) (caddr exp)) 136: (define (if-alternative exp) 137: (if (not (null? (cdddr exp))) 138: (cadddr exp) 139: 'false)) 140: 141: ;; if式を作る. 142: (define (make-if predicate consequent alternative) 143: (list 'if predicate consequent alternative)) 144: 145: ;; begin式であるか否かを判定する.また,beginの式の列, 146: ;; begin内の最後のであるかどうかの判定,最初の式の取り出し, 147: ;; 2番目以降の式の取り出し,式の列からbeginを作る関数の定義. 148: ;; 式が一つしかなければ,beginをつけない. 149: (define (begin? exp) (tagged-list? exp 'begin)) 150: (define (begin-actions exp) (cdr exp)) 151: (define (last-exp? seq) (null? (cdr seq))) 152: (define (first-exp seq) (car seq)) 153: (define (rest-exps seq) (cdr seq)) 154: (define (sequence->exp seq) 155: (cond ((null? seq) seq) 156: ((last-exp? seq) (first-exp seq)) 157: (else (make-begin seq)))) 158: (define (make-begin seq) (cons 'begin seq)) 159: 160: ;; 関数呼び出しか否かの判定.また,関数,引数の取り出し, 161: ;; 引数が無い場合の判定.引数がないかどうかの判定,最初の 162: ;; 引数,2番目以降の引数の取り出し. 163: (define (application? exp) (pair? exp)) 164: (define (operator exp) (car exp)) 165: (define (operands exp) (cdr exp)) 166: (define (no-operand? ops) (null? ops)) 167: (define (first-operand ops) (car ops)) 168: (define (rest-operands ops) (cdr ops)) 169: 170: ;; cond式か否かの判定.cond式の本体の取り出し,else節であるか 171: ;; どうかの判定,節の条件の取り出し,節の本体の取り出し, 172: ;; condをifに変換するための関数の定義. 173: (define (cond? exp) (tagged-list? exp 'cond)) 174: (define (cond-clauses exp) (cdr exp)) 175: (define (cond-else-clause? clause) 176: (eq? (cond-predicate clause) 'else)) 177: (define (cond-predicate clause) (car clause)) 178: (define (cond-actions clause) (cdr clause)) 179: (define (cond->if exp) 180: (expand-clauses (cond-clauses exp))) 181: (define (expand-clauses clauses) 182: (if (null? clauses) 183: 'false 184: (let ((first (car clauses)) 185: (rest (cdr clauses))) 186: (if (cond-else-clause? first) 187: (if (null? rest) 188: (sequence->exp (cond-actions first)) 189: (error "ELSE clause isn't last -- COND->IF" 190: clauses)) 191: (make-if (cond-predicate first) 192: (sequence->exp (cond-actions first)) 193: (expand-clauses rest)))))) 194: 195: ;; 真である(偽でない)ことの判定および,偽であることの判定. 196: (define (true? x) (not (eq? x #f))) 197: (define (false? x) (eq? x #f)) 198: 199: ;; let式であるか否かの判定.また,letで定義されている変数, 200: ;; それらに対応する式の取り出し.letの本体の取り出し. 201: ;; さらにlet式をlambdaを用いて書いたものに変換する関数の定義. 202: (define (let? exp) (tagged-list? exp 'let)) 203: (define (let-variables exp) (map car (cadr exp))) 204: (define (let-exps exp) (map cadr (cadr exp))) 205: (define (let-body exp) (cddr exp)) 206: (define (let->lambda exp) 207: (cons 208: (cons 'lambda 209: (cons (let-variables exp) (let-body exp))) 210: (let-exps exp))) 211: 212: ;; 関数本体の定義.関数本体であるか否かの判定,関数のパラメター, 213: ;; 関数の本体,関数の環境のそれぞれの取り出し. 214: (define (make-procedure parameters body env) 215: (list 'procedure parameters body env)) 216: (define (compound-procedure? p) 217: (tagged-list? p 'procedure)) 218: (define (procedure-parameters p) (cadr p)) 219: (define (procedure-body p) (caddr p)) 220: (define (procedure-environment p) (cadddr p)) 221: 222: ;; ある環境の親環境および直近のフレームの取り出し.最初の環境 223: ;; (中身のない環境.番兵として利用)の定義,フレームの変数列 224: ;; および値の列の取り出し,フレームへのバインディングの追加, 225: ;; 新たな環境の生成のための関数の定義.さらに変数の探索 226: ;; ための関数の定義. 227: (define (enclosing-environment env) (cdr env)) 228: (define (first-frame env) (car env)) 229: (define the-empty-environment '()) 230: (define (make-frame variables values) 231: (cons variables values)) 232: (define (frame-variables frame) (car frame)) 233: (define (frame-values frame) (cdr frame)) 234: (define (add-binding-to-frame! var val frame) 235: (set-car! frame (cons var (car frame))) 236: (set-cdr! frame (cons val (cdr frame)))) 237: (define (extend-environment vars vals base-env) 238: (if (= (length vars) (length vals)) 239: (cons (make-frame vars vals) base-env) 240: (if (< (length vars) (length vals)) 241: (error "Too many arguments supplied" vars vals) 242: (error "Too few arguments supplied" vars vals)))) 243: (define (lookup-variable-value var env) 244: (define (env-loop env) 245: (define (scan vars vals) 246: (cond ((null? vars) 247: (env-loop (enclosing-environment env))) 248: ((eq? var (car vars)) 249: (car vals)) 250: (else (scan (cdr vars) (cdr vals))))) 251: (if (eq? env the-empty-environment) 252: (error "Unbounded variable" var) 253: (let ((frame (first-frame env))) 254: (scan (frame-variables frame) 255: (frame-values frame))))) 256: (env-loop env)) 257: 258: ;; set!を実現するための関数. 259: (define (set-variable-value! var val env) 260: (define (env-loop env) 261: (define (scan vars vals) 262: (cond ((null? vars) 263: (env-loop (enclosing-environment env))) 264: ((eq? var (car vars)) 265: (set-car! vals val)) 266: (else (scan (cdr vars) (cdr vals))))) 267: (if (eq? env the-empty-environment) 268: (error "Unbound variable -- SET!" var) 269: (let ((frame (first-frame env))) 270: (scan (frame-variables frame) 271: (frame-values frame))))) 272: (env-loop env)) 273: ;; 現在の直近のフレームにバインディングを追加する. 274: (define (define-variable! var val env) 275: (let ((frame (first-frame env))) 276: (define (scan vars vals) 277: (cond ((null? vars) 278: (add-binding-to-frame! var val frame)) 279: ((eq? var (car vars)) 280: (set-car! vals val)) 281: (else (scan (cdr vars) (cdr vals))))) 282: (scan (frame-variables frame) 283: (frame-values frame)))) 284: 285: ;; 組み込み関数であるか否かの判定.ベースシステム上(この場合はkawa) 286: ;; 利用すべき関数. 287: (define (primitive-procedure? proc) 288: (tagged-list? proc 'primitive)) 289: (define (primitive-implementation proc) (cadr proc)) 290: 291: ;; 組み込み関数の定義.また,組み込み関数の名前,組み込み関数本体の生成 292: ;; のための関数の定義.さらにベースシステム上での組み込み関数の実行の 293: ;; ための関数. 294: (define primitive-procedures 295: `((car ,car) (cdr ,cdr) (cons ,cons) (null? ,null?) 296: (* ,*) (+ ,+) (- ,-) (/ ,/) (= ,=) (> ,>) (>= ,>=) (< ,<)(<= ,<=) 297: (not ,not) (and ,and) (or ,or) (display ,user-print) (newline ,newline) 298: (true? ,true?) (false? ,false?))) 299: (define (primitive-procedure-names) (map car primitive-procedures)) 300: (define (primitive-procedure-objects) 301: (map (lambda (proc) (list 'primitive (cadr proc))) 302: primitive-procedures)) 303: (define (apply-primitive-procedure proc args) 304: (apply-in-underlying-scheme 305: (primitive-implementation proc) args)) 306: 307: ;; 環境の初期化,大域環境の生成 308: (define (setup-environment) 309: (let ((initial-env 310: (extend-environment (primitive-procedure-names) 311: (primitive-procedure-objects) 312: the-empty-environment))) 313: (define-variable! 'true #t initial-env) 314: (define-variable! 'false #f initial-env) 315: initial-env)) 316: (define the-global-environment (setup-environment)) 317: 318: 319: ;; 数や式など表示のための関数.lambdaで定義した関数以外は 320: ;; ベースシステム(kawa)のものをそのまま用いる.lambdaで 321: ;; 作られたものは"compound-procedure"というキーワードと共に 322: ;; 引数や定義本体を表示する. 323: (define (user-print object) 324: (if (compound-procedure? object) 325: (display (list 'compound-procedure 326: (procedure-parameters object) 327: (procedure-body object) 328: '<procedure-env>)) 329: (display object))) 330: 331: ;; システムが立ち上がったときに基本的な関数を定義する. 332: (define (init-definitions) 333: (let loop ((defs '((define (zero? x) (= x 0)) 334: (define (cadr x) (car (cdr x))) 335: (define (cddr x) (cdr (cdr x))) 336: (define (cdar x) (cdr (car x))) 337: (define (caar x) (car (car x)))))) 338: (when (not (null? defs)) 339: (eval (car defs) the-global-environment) 340: (loop (cdr defs))))) 341: (init-definitions) 342: 343: 344: ;; REPL の本体.プロンプトを出して(read)で入力された式を手に 345: ;; 入れる. 346: (define (repl) 347: (display "my-scheme> ") 348: (let ((exp (read))) 349: (when (not (eq? exp #!eof)) 350: (display "==> ") 351: (user-print (eval exp the-global-environment)) 352: (newline) 353: (repl)))) 354: 355: (display "** Scheme in Scheme **") 356: (newline) 357: (repl) 358: (display "Bye, see you.") 359: (newline)) 360: 361: (myscheme) 362: 363: