Guest User

Untitled

a guest
Jan 21st, 2018
68
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Scheme 18.22 KB | None | 0 0
  1. ;#lang r5rs
  2. ;; (#%require (only racket/base
  3. ;;                  make-hasheq
  4. ;;                  hash-ref
  5. ;;                  hash-set!
  6. ;;                  raise-user-error))
  7. ; chicken
  8. (require-extension (srfi 69))
  9. ; racket
  10. ;; (#%require srfi/69
  11. ;;            srfi/23)
  12. (define raise-user-error error)
  13.  
  14. (define (apply. procedure arguments)
  15.   (cond ((primitive-procedure? procedure)
  16.          (apply-primitive-procedure procedure arguments))
  17.         ((compound-procedure? procedure)
  18.          (eval-sequence
  19.           (procedure-body procedure)
  20.           (extend-environment
  21.            (procedure-parameters procedure)
  22.            arguments
  23.            (procedure-environment procedure))))
  24.         (else (raise-user-error 'apply. "Unknown procedure type ~a" procedure))))
  25.  
  26. (define (eval. exp env)
  27.   (cond ((self-evaluating? exp) exp)
  28.         ((variable? exp) (lookup-variable-value exp env))
  29.         ((quoted? exp) (text-of-quotation exp))
  30.         ((get-stx (car exp)) => (lambda (f) (f exp env)))
  31.         ((application? exp)
  32.          (apply. (eval. (operator exp) env)
  33.                 (list-of-values (operands exp) env)))
  34.         (else (raise-user-error 'eval. "Unknown expression type ~a" exp))))
  35.  
  36.  
  37.  
  38.  
  39. ;; booleans
  40. ;; false is false, everything else is truthy.
  41. (define (sc-boolean? exp)
  42.   (or (eq? exp 'true)
  43.       (eq? exp 'false)))
  44. (define (true? exp)
  45.   (not (false? exp)))
  46. (define (false? exp)
  47.   (eq? exp 'false))
  48.  
  49. ;; undefined is used in the expansion of some macros
  50. (define (*undefined*)
  51.   '*undefined*)
  52. ;; void is used when a value should not be returned
  53. (define (*void*)
  54.   '*void*)
  55. (define (void? exp)
  56.   (or (eq? exp (*void*))
  57.       (tagged-list? exp (*void*))))
  58.  
  59.  
  60. (define (undefined? exp)
  61.   (eq? exp (*undefined*)))
  62. (define syntaxes (make-hash-table))
  63. (define (get-stx id) (hash-table-ref syntaxes id (lambda () #f)))
  64. (define (put-stx! id exp) (hash-table-set! syntaxes id exp))
  65.  
  66. (define (initialize-stx)
  67.   (begin
  68.     (put-stx! 'void   (*void*))
  69.     (put-stx! 'quote  eval-quoted)
  70.     (put-stx! 'lambda eval-lambda)
  71.     (put-stx! 'cond   eval-cond)
  72.     (put-stx! 'begin  eval-begin)
  73.     (put-stx! 'set!   eval-assignment)
  74.     (put-stx! 'define eval-definition)
  75.     (put-stx! 'if     eval-if)
  76.     (put-stx! 'and    eval-and)
  77.     (put-stx! 'or     eval-or)
  78.     (put-stx! 'let    eval-let)
  79.     (put-stx! 'let*   eval-let*)
  80.     (put-stx! 'letrec eval-letrec)))
  81.  
  82. (define (eval-quoted exp env) (text-of-quotation exp))
  83.  
  84. (define (eval-cond exp env) (eval. (cond->if exp) env))
  85.  
  86. (define (eval-begin exp env)
  87.   (eval-sequence (begin-actions exp) env))
  88.  
  89. (define (eval-lambda exp env)
  90.   (make-procedure (lambda-parameters exp)
  91.                   (lambda-body exp)
  92.                   env))
  93.  
  94.  
  95. (define (eval-let* exp env)
  96.   (eval. (let*->let exp) env))
  97.  
  98. (define (list-of-values exps env)
  99.     (if (no-operands? exps) '()
  100.         (cons (eval. (first-operand exps) env)
  101.               (list-of-values (rest-operands exps) env))))
  102.  
  103. (define (eval-if exp env)
  104.   (if (true? (eval. (if-predicate exp) env))
  105.       (eval. (if-consequent exp) env)
  106.       (eval. (if-alternative exp) env)))
  107.  
  108.  
  109. (define (eval-sequence exps env)
  110.   (cond ((last-exp? exps) (eval. (first-exp exps) env))
  111.         (else (eval. (first-exp exps) env)
  112.               (eval-sequence (rest-exps exps) env))))
  113. (define (eval-assignment exp env)
  114.   (set-variable-value! (assignment-variable exp)
  115.                        (eval. (assignment-value exp) env)
  116.                        env)
  117.   (*void*))
  118. (define (eval-definition exp env)
  119.   (define-variable! (definition-variable exp)
  120.                     (eval. (definition-value exp) env)
  121.                     env)
  122.    (*void*))
  123. (define (self-evaluating? exp)
  124.   (cond ((void? exp)    #t)
  125.         ((number? exp)  #t)
  126.         ((string? exp)  #t)
  127.         ((sc-boolean? exp) #t)
  128.         (else #f)))
  129. (define (variable? exp) (symbol? exp))
  130. (define (quoted? exp)
  131.   (tagged-list? exp 'quote))
  132.  
  133. (define (text-of-quotation exp) (cadr exp))
  134. (define (tagged-list? exp tag)
  135.   (if (pair? exp)
  136.       (eq? (car exp) tag)
  137.       #f))
  138. (define (assignment? exp)
  139.   (tagged-list? exp 'set!))
  140. (define (make-assignment var binding) `(set! ,var ,binding))
  141. (define (assignment-variable exp) (cadr exp))
  142. (define (assignment-value exp) (caddr exp))
  143.  
  144. (define (definition? exp)
  145.   (tagged-list? exp 'define))
  146. (define (definition-variable exp)
  147.   (if (symbol? (cadr exp))
  148.       (cadr exp)
  149.       (caadr exp)))
  150. (define (make-definition var binding)
  151.   `(define ,var ,binding))
  152.  
  153. (define (definition-value exp)
  154.   (if (symbol? (cadr exp))
  155.       (caddr exp)
  156.       (make-lambda (cdadr exp)   ; formal parameters
  157.                    (cddr exp)))) ; body
  158.  
  159. (define (lambda? exp) (tagged-list? exp 'lambda))
  160. (define (lambda-parameters exp) (cadr exp))
  161. (define (lambda-body exp) (cddr exp))
  162. (define (make-lambda parameters body)
  163.   (cons 'lambda (cons parameters body)))
  164.  
  165. (define (if? exp) (tagged-list? exp 'if))
  166. (define (if-predicate exp) (cadr exp))
  167. (define (if-consequent exp) (caddr exp))
  168. (define (if-alternative exp)
  169.   (if (not (null? (cdddr exp)))
  170.       (cadddr exp)
  171.       (*void*)))
  172.  
  173. (define (make-if predicate consequent alternative)
  174.   (list 'if predicate consequent alternative))
  175.  
  176.  
  177. (define (begin? exp) (tagged-list? exp 'begin))
  178. (define (begin-actions exp) (cdr exp))
  179.  
  180. (define (last-exp? seq) (null? (cdr seq)))
  181. (define (first-exp seq) (car seq))
  182. (define (rest-exps seq) (cdr seq))
  183.  
  184. (define (sequence->exp seq)
  185.   (cond ((null? seq) seq)
  186.         ((last-exp? seq) (first-exp seq))
  187.         (else (make-begin seq))))
  188.  
  189. (define (make-begin seq) (cons 'begin seq))
  190.  
  191.  
  192.  
  193. (define (application? exp) (pair? exp))
  194. (define (operator exp) (car exp))
  195. (define (operands exp) (cdr exp))
  196. (define (no-operands? ops) (null? ops))
  197. (define (first-operand ops) (car ops))
  198. (define (rest-operands ops) (cdr ops))
  199. ;;  Macros
  200. ;;
  201. ;;  Cond
  202.  
  203. ;; These functions perform the tranformation of
  204. ;;
  205. ;; (cond (<test1> <actions1>)
  206. ;;       (<test2> <actions2>)
  207. ;;       ...
  208. ;;       (<testn> <actionsn>))
  209. ;;
  210. ;; into
  211. ;;
  212. ;; (if <test1> (begin <actions1>)
  213. ;;     (if <test2> (begin <actions2>) ...
  214. ;;         (if <testn> (begin <actionsn>))))
  215. ;;
  216. ;; where the last test, <testn>, may optionally
  217. ;; be replaced by the symbol 'else.  This implementation
  218. ;; of cond supports the SFRI-34 style cond arrow syntax,
  219. ;; (<test> => <recipient>), which is transformed into
  220. ;; (if (<test>) (<recipient> <test>))
  221.  
  222. ;; cond is a list of
  223. ;; (cond <clauses>)
  224.  
  225. (define (cond? exp)
  226.   (tagged-list? exp 'cond))
  227. (define (cond-clauses exp)
  228.   (cdr exp))
  229. ;; each clause is a list of (<predicate> <actions>)
  230.  
  231. (define (cond-predicate clause)
  232.   (car clause))
  233. (define (cond-actions clause)
  234.   (cdr clause))
  235.  
  236. (define (cond-else-clause? clause)
  237.   (eq? (cond-predicate clause) 'else))
  238.  
  239. (define (cond->if exp)
  240.   (expand-clauses (cond-clauses exp)))
  241.  
  242. (define (cond-arrow-clause? exp)
  243.   (and (list? exp)
  244.        (not (null? (cdr exp)))
  245.        (eq? (cadr exp) '=>)))
  246.  
  247. (define (cond-arrow-test exp) (car exp))
  248.  
  249. (define (cond-arrow-recipient exp) (caddr exp))
  250.  
  251. (define (expand-clauses clauses)
  252.   (if (null? clauses) 'false
  253.       (let ((first (car clauses))
  254.             (rest (cdr clauses)))
  255.         (if (cond-arrow-clause? first)
  256.             (make-if (cond-predicate first)
  257.                      (list (cond-arrow-recipient first)
  258.                            (cond-arrow-test first))
  259.                      (expand-clauses rest))
  260.             (if (cond-else-clause? first)
  261.                 (if (null? rest)
  262.                     (sequence->exp (cond-actions first))
  263.                     (raise-user-error 'cond "ELSE clause isn't last ~a" clauses))
  264.                 (make-if (cond-predicate first)
  265.                          (sequence->exp (cond-actions first))
  266.                          (expand-clauses rest)))))))
  267. ; and
  268. (define (and? exp) (tagged-list? exp 'and))
  269. (define (eval-and exp env)
  270.   (let and-loop ((exp (cdr exp))
  271.                  (last 'true))
  272.     (cond ((null? exp) last)
  273.           ((false? last) 'false)
  274.           (else (and-loop (cdr exp)
  275.                           (eval. (car exp) env))))))
  276.  
  277. ; or
  278. (define (or? exp) (tagged-list? exp 'or))
  279. (define (eval-or exp env)
  280.   (let or-loop ((exp (cdr exp)))
  281.     (if (null? exp) 'false
  282.         (let ((evaled (eval. (car exp) env)))
  283.           (if (true? evaled) evaled
  284.               (or-loop (cdr exp)))))))
  285.  
  286.  
  287.  
  288. ; let
  289.  
  290. (define (let? exp) (tagged-list? exp 'let))
  291.  
  292. (define (let-bindings exp)
  293.   (cadr exp))
  294.  
  295. (define (let-body exp)
  296.   (caddr exp))
  297.  
  298. ;; todo: make more of the code use the function below.
  299. (define (make-let bindings body)
  300.   `(let ,bindings ,body))
  301.  
  302.  
  303. (define (let-get-vars/exprs f)
  304.   (lambda (exp)
  305.     (define (rec-let-get-vars/exprs binding-list acc-list)
  306.       (cond ((null? binding-list) (reverse acc-list))
  307.             ((not (pair? (car binding-list)))
  308.              (raise-user-error 'let "Not a variable-expression pair in let-clause ~a" exp))
  309.             (else (rec-let-get-vars/exprs (cdr binding-list) (cons (f (car binding-list)) acc-list)))))
  310.     (rec-let-get-vars/exprs (let-bindings exp) '())))
  311.  
  312. (define let-exprs (let-get-vars/exprs cadr))
  313.  
  314. (define let-vars (let-get-vars/exprs car))
  315.  
  316. (define (eval-let exp env)
  317.   (eval. (let->combination exp) env))
  318.  
  319. ; let*
  320. (define (let*? exp) (tagged-list? exp 'let*))
  321. (define (let*->let exp)
  322.   (if (<= (length (let-bindings exp)) 1)
  323.       `(let ,(let-bindings exp) ,(let-body exp))
  324.       `(let (,(car (let-bindings exp)))
  325.          ,(let*->let `(let* ,(cdr (let-bindings exp)) ,(let-body exp))))))
  326.  
  327. (define (named-let? exp)
  328.   (and (eq? (car exp) 'let)
  329.        (symbol? (cadr exp))))
  330.  
  331. ; named-let
  332. (define (named-let-body exp) (cadddr exp))
  333.  
  334. (define (named-let-bindings exp) (caddr exp))
  335.  
  336. (define (named-let-name exp) (cadr exp))
  337.  
  338. (define (named-let-vars exp)
  339.   (map car (named-let-bindings exp)))
  340.  
  341. (define (named-let-inits exp)
  342.   (map cadr (named-let-bindings exp)))
  343.  
  344. (define (expand-named-let exp)
  345.   (sequence->exp
  346.    `((define (,(named-let-name exp) ,@(named-let-vars exp)) ,(named-let-body exp))
  347.      (,(named-let-name exp) ,@(named-let-inits exp)))))
  348.  
  349.  
  350. (define (let->combination exp)
  351.   (if (named-let? exp)
  352.       (expand-named-let exp)
  353.       (if (null? (let-body exp))
  354.           (raise-user-error 'let "Body of let clause must not be empty ~a" exp)
  355.           (cons (make-lambda (let-vars exp) (list (let-body exp)))
  356.                 (let-exprs exp)))))
  357.  
  358.  
  359. ;; letrec implements the transformation of
  360. ;; (letrec
  361. ;;     ((<var> <expr>) ...)
  362. ;;   body)
  363. ;; into
  364. ;; (let ((<var> '*undefined*)...)
  365. ;;   (set! var <expr>)
  366. ;;   ...)
  367. (define (letrec? exp)
  368.   (tagged-list? exp 'letrec))
  369. (define (letrec-bindings expr)
  370.   (cadr expr))
  371. (define (letrec-body expr)
  372.   (cddr expr))
  373.  
  374. (define (transform-letrec exp)
  375.   (make-let
  376.    (map (lambda (binding)
  377.           (list (car binding) `(quote ,(*undefined*))))
  378.         (letrec-bindings exp))
  379.    (make-begin
  380.     (append
  381.      (map (lambda (binding)
  382.             (make-assignment
  383.              (car binding)
  384.              (cadr binding)))
  385.           (letrec-bindings exp))
  386.      (letrec-body exp)))))
  387. (define (eval-letrec exp env)
  388.   (eval. (transform-letrec exp) env))
  389. ;; test:
  390. ;; (transform-letrec '(letrec ((even?
  391. ;;                              (lambda (n)
  392. ;;                                (if (= n 0) true
  393. ;;                                    (odd? (- n 1)))))
  394. ;;                             (odd?
  395. ;;                              (lambda (n)
  396. ;;                                (if (= n 0) false
  397. ;;                                    (odd? (- n 1))))))
  398. ;;                      (even? x)))
  399.  
  400. ;; scan-out-defines: basically implements letrec-like transformation
  401. ;; for inner defines.  this is necessary, in order for things like
  402.  ;; '(define (f x)
  403.  ;;   (define (even? n)
  404.  ;;     (if (= n 0) true
  405.  ;;         (odd? (- n 1))))
  406.  ;;   (define (odd? n)
  407.  ;;     (if (= n 0) false
  408.  ;;         (even? (- n 1))))
  409.  ;;   (even? x))
  410. ;; to be guaranteed to have both even? and odd? defined at the right time.
  411.  
  412. (define (scan-out-defines exp-body)
  413.   (let* ((defs+other
  414.            (let scan
  415.              ((exp exp-body) (defs '()) (other '()))
  416.              (if (null? exp) (cons (reverse defs) (reverse other))
  417.                  (if (definition? (car exp))
  418.                      (scan (cdr exp)
  419.                            (cons (car exp) defs)
  420.                            other)
  421.                      (scan (cdr exp)
  422.                            defs
  423.                            (cons (car exp) other))))))
  424.          (defs (car defs+other))
  425.          (other (cdr defs+other)))
  426.     (if (null? defs) exp-body
  427.         (begin (display defs) (newline)
  428.          (list
  429.           (make-let (map (lambda (def)
  430.                            `(,(definition-variable def)
  431.                              (quote ,(*undefined*))))
  432.                          defs)
  433.                     (make-begin
  434.                      (append
  435.                       (map (lambda (def)
  436.                              (make-assignment
  437.                               (definition-variable def)
  438.                               (definition-value def)))
  439.                            defs)
  440.                       other))))))))
  441.  
  442.  
  443. ; procedures
  444.  
  445. (define (make-procedure parameters body env)
  446.   (list 'procedure parameters (scan-out-defines body) env))
  447.  
  448. (define (compound-procedure? p) (tagged-list? p 'procedure))
  449.  
  450. (define (procedure-parameters p) (cadr p))
  451.  
  452. (define (procedure-body p) (caddr p))
  453.  
  454. (define (procedure-environment p) (cadddr p))
  455.  
  456. ;; environment and env. frames
  457.  
  458. (define (enclosing-environment env) (cdr env))
  459.  
  460. (define (first-frame env) (car env))
  461.  
  462. (define the-empty-environment '())
  463.  
  464. (define (make-frame variables values)
  465.   (cons variables values))
  466.  
  467. (define (frame-variables frame)
  468.   (car frame))
  469.  
  470. (define (frame-values frame)
  471.   (cdr frame))
  472.  
  473. (define (find-binding-in-frame frame var)
  474.   (let scan ((vars (frame-variables frame))
  475.              (vals (frame-values frame)))
  476.     (cond ((null? vars)
  477.            (cons #f '()))
  478.           ((eq? var (car vars))
  479.            (cons #t (car vals)))
  480.           (else (scan (cdr vars) (cdr vals))))))
  481.  
  482. (define (set-binding-in-frame! frame var val)
  483.   (let scan ((vars (frame-variables frame))
  484.              (vals (frame-values frame)))
  485.     (cond ((null? vars) #f)
  486.           ((eq? var (car vars))
  487.            (set-car! vals val) #t)
  488.           (else (scan (cdr vars) (cdr vals))))))
  489.  
  490. (define (add-binding-to-frame! frame var val)
  491.   (set-car! frame (cons var (car frame)))
  492.   (set-cdr! frame (cons val (cdr frame))))
  493.  
  494. (define (lookup-variable-value var env)
  495.       (let env-loop ((cenv env))
  496.         (if (eq? cenv the-empty-environment)
  497.             (raise-user-error "Unbound variable!" var)
  498.             (let ((result (find-binding-in-frame (first-frame cenv) var)))
  499.               (if (car result)
  500.                   (if (eq? (cdr result) (*undefined*))
  501.                       (raise-user-error "Variable is not yet defined: " var)
  502.                       (cdr result))
  503.                   (env-loop (enclosing-environment cenv)))))))
  504.  
  505. (define (set-variable-value! var val env)
  506.   (let env-loop ((cenv env))
  507.     (if (eq? cenv the-empty-environment)
  508.         (raise-user-error "Unbound Variable!" var)
  509.         (if (set-binding-in-frame! (first-frame cenv) var val)
  510.             (*void*)
  511.             (env-loop (enclosing-environment cenv))))))
  512.  
  513. (define (define-variable! var val env)
  514.   (let ((frame (first-frame env)))
  515.     (if (set-binding-in-frame! frame var val)
  516.         (*void*)
  517.         (add-binding-to-frame! frame var val))))
  518.  
  519.  
  520.  
  521.  
  522.  
  523.  
  524. (define (extend-environment vars vals base-env)
  525.   (if (= (length vars) (length vals))
  526.       (cons (make-frame vars vals) base-env)
  527.       (raise-user-error
  528.        'extend-environment
  529.        "Binding expression unbalanced! ~nvars: ~a~nexpressions: ~a"
  530.        vars vals)))
  531.  
  532. ; primitives
  533.  
  534. (define (primitive-procedure? proc)
  535.   (tagged-list? proc 'primitive))
  536.  
  537. (define (primitive-implementation proc)
  538.   (cadr proc))
  539.  
  540. (define (make-boolean-expr test)
  541.   (lambda args (if (apply test args) 'true 'false)))
  542.  
  543. (define primitive-procedures
  544.   `((car   ,car)
  545.     (cdr   ,cdr)
  546.     (cons  ,cons)
  547.     (null? ,(make-boolean-expr null?))
  548.     (list  ,list)
  549.     (+     ,+)
  550.     (-     ,-)
  551.     (/     ,/)
  552.     (*     ,*)
  553.     (=     ,(make-boolean-expr =))
  554.     (>     ,(make-boolean-expr >))
  555.     (<     ,(make-boolean-expr <))
  556.     (eq?   ,(make-boolean-expr eq?))
  557.     (<=    ,(make-boolean-expr <=))
  558.     (>=    ,(make-boolean-expr >=))
  559.     (sin   ,sin)
  560.     (cos   ,cos)
  561.     (tan   ,tan)
  562.     (expt  ,expt)))
  563.  
  564. (define (primitive-procedure-names)
  565.   (map car primitive-procedures))
  566.  
  567. (define (primitive-procedure-objects)
  568.   (map
  569.    (lambda (proc) (list 'primitive (cadr proc)))
  570.    primitive-procedures))
  571.  
  572. ;; setup
  573.  
  574. (define (setup-environment)
  575.   (let ((initial-env
  576.          (extend-environment (primitive-procedure-names)
  577.                              (primitive-procedure-objects)
  578.                              the-empty-environment)))
  579.     (define-variable! 'true  'true initial-env)
  580.     (define-variable! 'false 'false initial-env)
  581.     initial-env))
  582.  
  583. (define the-global-environment (setup-environment))
  584.  
  585. (define (apply-primitive-procedure proc args)
  586.   (apply ; no period, so this scheme's apply
  587.    (primitive-implementation proc) args))
  588.  
  589.  
  590. (initialize-stx)
  591.  
  592. ;; finally, input for the interpreter
  593.  
  594. (define input-prompt  "~> ")
  595.  
  596. (define (interpret exp) (eval. exp the-global-environment))
  597.  
  598. (define (driver-loop)
  599.   (prompt-for-input input-prompt)
  600.   (let ((input (read)))
  601.     (cond ((and (not (eof-object? input))
  602.                 (not (eq? input 'exit)))
  603.               (let ((evaled (interpret input)))
  604.                 (user-print evaled)
  605.                 (driver-loop)))
  606.            (else
  607.             (newline)
  608.             (display "GOODBYE.")
  609.             (newline)))))
  610.  
  611. (define (prompt-for-input str)
  612.   (begin
  613.     (display str)))
  614.  
  615. (define (user-print object)
  616.   (cond ((void? object) (if #f #f))
  617.         ((compound-procedure? object)
  618.          (display (list 'compound-procedure
  619.                         (procedure-parameters object)
  620.                         (procedure-body object)
  621.                         '<procedure-env>))
  622.          (newline))
  623.         (else (display object)
  624.               (newline))))
  625. (define (start)
  626.     (display "WELCOME TO SCHEME.")
  627.     (newline)
  628.     (driver-loop))
  629. (start)
Add Comment
Please, Sign In to add comment