Advertisement
timothy235

sicp-4-1-4-repl-program

Mar 12th, 2017
192
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Racket 17.72 KB | None | 0 0
  1. #lang racket
  2. (require racket/mpair)
  3. (provide (all-defined-out))
  4.  
  5. ;; This is the repl program through the exercises of section 4.1.4.
  6. ;; Use "4-1-4-repl-test.rkt" to test basic functionality.
  7.  
  8. ;; NOTES:
  9.  
  10. ;; 1. Environments are mutable lists.  All other lists are regular immutable lists.
  11. ;; 2. We use the implementation for frames from exercises 4.11 and 4.12.
  12. ;; 3. Book terms that shadow Racket built-ins are prefixed with my-.
  13. ;; 4. The alternate cond test, when true, will be inefficiently evaluated twice.
  14. ;; 5. The body of a lambda or let statement can be a sequence.
  15.  
  16. ;; PROGRAM SECTIONS:
  17.  
  18. ;; 1. my-eval and my-apply
  19. ;; 2. eval procedures
  20. ;; 3. self-evaluating expressions, variables, and quotations
  21. ;; 4. definition and assignment
  22. ;; 5. lambdas, procedures and applications
  23. ;; 6. sequences and begin expressions
  24. ;; 7. boolean expressions
  25. ;; 8. if and cond expressions
  26. ;; 9. let, let*, and named-let
  27. ;; 10. environment and frames
  28. ;; 11. primitive procedures and the global environment
  29. ;; 12. repl operations
  30.  
  31. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  32. ;; 1. MY-EVAL AND MY-APPLY  ;;
  33. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  34.  
  35. (define (my-eval expr env)
  36.   (cond [(self-evaluating? expr) expr]
  37.         [(variable? expr) (lookup-variable-value expr env)]
  38.         [(quoted? expr) (text-of-quotation expr)]
  39.         [(definition? expr) (eval-definition expr env)]
  40.         [(assignment? expr) (eval-assignment expr env)]
  41.         [(if? expr) (eval-if expr env)]
  42.         [(cond? expr) (my-eval (cond->if expr) env)]
  43.         [(begin? expr) (eval-sequence (begin-actions expr) env)]
  44.         [(and? expr) (eval-and expr env)]
  45.         [(or? expr) (eval-or expr env)]
  46.         [(let? expr) (my-eval (let->combination expr) env)]
  47.         [(let*? expr) (my-eval (let*->nested-lets expr) env)]
  48.         [(named-let? expr) (my-eval (named-let->sequence expr) env)]
  49.         [(lambda? expr)
  50.          (make-procedure (lambda-parameters expr)
  51.                          (lambda-body expr)
  52.                          env)]
  53.         [(application? expr)
  54.          (my-apply (my-eval (operator expr) env)
  55.                    (list-of-values (operands expr) env))]
  56.         [else (error "Unknown expression type -- MY-EVAL" expr)]))
  57.  
  58. (define (my-apply procedure arguments)
  59.   (cond [(primitive-procedure? procedure)
  60.          (apply-primitive-procedure procedure arguments)]
  61.         [(compound-procedure? procedure)
  62.          (eval-sequence
  63.            (procedure-body procedure)
  64.            (extend-environment
  65.              (procedure-parameters procedure)
  66.              arguments
  67.              (procedure-environment procedure)))]
  68.         [else (error "Unknown procedure type -- APPLY" procedure)]))
  69.  
  70. ;;;;;;;;;;;;;;;;;;;;;;;;;
  71. ;; 2. EVAL PROCEDURES  ;;
  72. ;;;;;;;;;;;;;;;;;;;;;;;;;
  73.  
  74. (define (eval-definition expr env)
  75.   (define-variable! (definition-variable expr)
  76.                     (my-eval (definition-value expr) env)
  77.                     env)
  78.   'ok)
  79. (define (eval-assignment expr env)
  80.   (set-variable-value! (assignment-variable expr)
  81.                        (my-eval (assignment-value expr) env)
  82.                        env)
  83.   'ok)
  84. (define (list-of-values exprs env)
  85.   (if (no-operands? exprs)
  86.     empty
  87.     (cons (my-eval (first-operand exprs) env)
  88.           (list-of-values (rest-operands exprs) env))))
  89. (define (eval-sequence exprs env)
  90.   (cond [(last-exp? exprs) (my-eval (first-exp exprs) env)]
  91.         [else (my-eval (first-exp exprs) env)
  92.               (eval-sequence (rest-exps exprs) env)]))
  93. (define (eval-if expr env)
  94.   (if (true? (my-eval (if-predicate expr) env))
  95.     (my-eval (if-consequent expr) env)
  96.     (my-eval (if-alternative expr) env)))
  97. (define (eval-and expr env)
  98.   (define ops (and-operands expr))
  99.   (cond [(empty? ops) 'true] ; (and) should be true
  100.         [else
  101.           (define val (my-eval (first ops) env))
  102.           (define rest-ops (rest ops))
  103.           (cond [(empty? rest-ops) val] ; (and x) should be x
  104.                 [(false? val) false]
  105.                 [else
  106.                   (eval-and (make-and rest-ops) env)])]))
  107. (define (eval-or expr env)
  108.   (define ops (or-operands expr))
  109.   (cond [(empty? ops) 'false] ; (or) should be false
  110.         [else
  111.           (define val (my-eval (first ops) env))
  112.           (define rest-ops (rest ops))
  113.           (cond [(empty? rest-ops) val] ; (or x) should be x
  114.                 [(not (false? val)) val]
  115.                 [else
  116.                   (eval-or (make-or rest-ops) env)])]))
  117.  
  118. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  119. ;; 3. SELF-EVALUATING EXPRESSIONS, VARIABLES, AND QUOTATIONS  ;;
  120. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  121.  
  122. (define (tagged-list? expr tag)
  123.   (if (pair? expr)
  124.     (eq? (first expr) tag)
  125.     false))
  126.  
  127. ;; Only numbers and strings are self-evaluating.
  128. (define (self-evaluating? expr)
  129.   (cond [(number? expr) true]
  130.         [(string? expr) true]
  131.         [else false]))
  132.  
  133. (define (variable? expr)
  134.   (symbol? expr))
  135.  
  136. ;; Quotations have the form:  (quote <text-of-quotation>)
  137. (define (quoted? expr)
  138.   (tagged-list? expr 'quote))
  139. (define (text-of-quotation expr)
  140.   (second expr))
  141.  
  142. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  143. ;; 4. DEFINITION AND ASSIGNMENT  ;;
  144. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  145.  
  146. ;; Variable definitions have the form:  (define <var> <value>)
  147.  
  148. ;; Procedure definitions have the form:
  149. ;; (define (<var> <parameter-1> ... <parameter-n>) <body>)
  150. ;; which is equivalent to:
  151. ;; (define <var> (lambda (<parameter-1> ... <parameter-n>) <body>))
  152.  
  153. (define (definition? expr) (tagged-list? expr 'define))
  154. (define (definition-variable expr)
  155.   (if (symbol? (second expr))
  156.     (second expr)
  157.     (first (second expr))))
  158. (define (definition-value expr)
  159.   (if (symbol? (second expr))
  160.     (third expr)
  161.     (make-lambda (rest (second expr)) ; formal parameters
  162.                  (drop expr 2))))
  163.  
  164. ;; Assignments have the form:  (set! <var> <value>)
  165. (define (assignment? expr)
  166.   (tagged-list? expr 'set!))
  167. (define (assignment-variable expr) (second expr))
  168. (define (assignment-value expr) (third expr))
  169.  
  170. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  171. ;; 5. LAMBDAS, PROCEDURES AND APPLICATIONS  ;;
  172. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  173.  
  174. ;; Lambda expressions have the form:
  175. ;; (lambda (<parameters>) <body>)
  176. (define (lambda? expr) (tagged-list? expr 'lambda))
  177. (define (lambda-parameters expr) (second expr))
  178. (define (lambda-body expr)
  179.   (drop expr 2))
  180. (define (make-lambda parameters body)
  181.   (cons 'lambda (cons parameters body)))
  182.  
  183. ;; Procedures:
  184. (define (make-procedure parameters body env)
  185.   (list 'procedure parameters body env))
  186. (define (compound-procedure? p)
  187.   (tagged-list? p 'procedure))
  188. (define (procedure-parameters p) (second p))
  189. (define (procedure-body p) (third p))
  190. (define (procedure-environment p) (fourth p))
  191.  
  192. ;; Procedure applications have the from:
  193. ;; (<var> <parameter> ...)
  194. (define (application? expr) (pair? expr))
  195. (define (operator expr) (first expr))
  196. (define (operands expr) (rest expr))
  197. (define (no-operands? ops) (empty? ops))
  198. (define (first-operand ops) (first ops))
  199. (define (rest-operands ops) (rest ops))
  200.  
  201. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  202. ;; 6. SEQUENCES AND BEGIN EXPRESSIONS  ;;
  203. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  204.  
  205. ;; Begin has the form:  (begin <actions>)
  206. (define (begin? expr) (tagged-list? expr 'begin))
  207. (define (begin-actions expr) (rest expr))
  208. (define (last-exp? seq) (empty? (rest seq)))
  209. (define (first-exp seq) (first seq))
  210. (define (rest-exps seq) (rest seq))
  211. (define (sequence->exp seq)
  212.   (cond [(empty? seq) seq]
  213.         [(last-exp? seq) (first-exp seq)]
  214.         [else (make-begin seq)]))
  215. ;; begin constructor used by cond->if
  216. (define (make-begin seq) (cons 'begin seq))
  217.  
  218. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  219. ;; 7. BOOLEAN EXPRESSIONS  ;;
  220. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  221.  
  222. (define (true? x) (not (false? x)))
  223. (define (and? expr) (tagged-list? expr 'and))
  224. (define (and-operands expr) (rest expr))
  225. (define (make-and sequence) (cons 'and sequence))
  226. (define (or? expr) (tagged-list? expr 'or))
  227. (define (or-operands expr) (rest expr))
  228. (define (make-or sequence) (cons 'or sequence))
  229.  
  230. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  231. ;; 8. IF AND COND EXPRESSIONS  ;;
  232. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  233.  
  234. ;; Conditionals have the form:  (if <predicate> <consequent> <alternative>)
  235. ;; If no alternative, use false.
  236. (define (if? expr) (tagged-list? expr 'if))
  237. (define (if-predicate expr) (second expr))
  238. (define (if-consequent expr) (third expr))
  239. (define (if-alternative expr)
  240.   (if (not (empty? (drop expr 3)))
  241.     (fourth expr)
  242.     'false))
  243. (define (make-if predicate consequent alternative)
  244.   (list 'if predicate consequent alternative))
  245.  
  246. ;; Cond has the form:
  247. ;; (cond ((<predicate> <actions>)
  248.        ;; (else <actions>))) ; if no else, assume (else false) clause
  249. (define (cond? expr) (tagged-list? expr 'cond))
  250. (define (cond-clauses expr) (rest expr))
  251. ;; regular cond clause
  252. (define (cond-predicate clause) (first clause))
  253. (define (cond-actions clause) (rest clause))
  254. ;; alternate test clause
  255. (define (cond-alternate-clause? clause)
  256.   (eq? (second clause) '=>))
  257. (define (cond-test clause) (first clause))
  258. (define (cond-recipient clause) (third clause))
  259. ;; else clause
  260. (define (cond-else-clause? clause)
  261.   (eq? (cond-predicate clause) 'else))
  262. ;; derive cond from if
  263. (define (cond->if expr)
  264.   (expand-clauses (cond-clauses expr)))
  265. (define (expand-clauses clauses)
  266.   (cond [(empty? clauses) 'false] ; no else clause
  267.         [else
  268.           (define first-clause (first clauses))
  269.           (define rest-clauses (rest clauses))
  270.           (cond [(cond-else-clause? first-clause)
  271.                  (if (empty? rest-clauses)
  272.                    (sequence->exp (cond-actions first-clause))
  273.                    (error "ELSE clause isn't last -- COND->IF" clauses))]
  274.                 [(cond-alternate-clause? first-clause)
  275.                  (define test (cond-test first-clause)) ; gets evaluated twice
  276.                  (make-if test
  277.                           (list (cond-recipient first-clause)
  278.                                 test)
  279.                           (expand-clauses rest-clauses))]
  280.                 [else
  281.                   (make-if (cond-predicate first-clause)
  282.                            (sequence->exp (cond-actions first-clause))
  283.                            (expand-clauses rest-clauses))])]))
  284.  
  285. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  286. ;; 9. LET, LET*, AND NAMED-LET  ;;
  287. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  288.  
  289. ;; Let has the form:  (let (<bindings>) <body>)
  290. (define (let? expr)
  291.   (and (tagged-list? expr 'let)
  292.        (list? (second expr))))
  293. (define (let-bindings expr) (second expr))
  294. (define (let-parameters expr) (map first (let-bindings expr)))
  295. (define (let-expressions expr) (map second (let-bindings expr)))
  296. (define (let-body expr) (drop expr 2))
  297. (define (let->combination expr)
  298.   (cond [(empty? (let-bindings expr)) ; do not unnecessarily lambda wrap
  299.          (sequence->exp (let-body expr))]
  300.         [else
  301.           (cons (make-lambda (let-parameters expr)
  302.                              (let-body expr))
  303.                 (let-expressions expr))]))
  304. (define (make-let bindings body)
  305.   (cons 'let (cons bindings body)))
  306.  
  307. ;; Let* has the same form as let, but bindings are sequential.
  308. (define (let*? expr) (tagged-list? expr 'let*))
  309. (define (let*-bindings expr) (second expr))
  310. (define (let*-body expr) (drop expr 2))
  311. (define (make-let* bindings body)
  312.   (cons 'let* (cons bindings body)))
  313. (define (let*->nested-lets expr)
  314.   (define bindings (let*-bindings expr))
  315.   (cond [(empty? bindings)
  316.          (sequence->exp (let-body expr))]
  317.         [else
  318.           (list 'let
  319.                 (list (first bindings))
  320.                 (let*->nested-lets
  321.                   (make-let* (rest bindings)
  322.                              (let-body expr))))]))
  323.  
  324. ;; Named-let has the form:  (let <name> (<bindings>) <body>)
  325. (define (named-let? expr)
  326.   (and (tagged-list? expr 'let)
  327.        (not (list? (second expr)))))
  328. (define (named-let-name expr) (second expr))
  329. (define (named-let-bindings expr) (third expr))
  330. (define (named-let-parameters expr) (map first (named-let-bindings expr)))
  331. (define (named-let-expressions expr) (map second (named-let-bindings expr)))
  332. (define (named-let-body expr) (drop expr 3))
  333. (define (named-let->sequence expr)
  334.   (define bindings (named-let-bindings expr))
  335.   (cond [(empty? bindings)
  336.          (sequence->exp (named-let-body expr))]
  337.         [else
  338.           (list 'begin
  339.                 (cons 'define ; first define the named function
  340.                       (cons (cons (named-let-name expr)
  341.                                   (named-let-parameters expr))
  342.                             (named-let-body expr)))
  343.                 (cons (named-let-name expr) ; then apply it to the expressions
  344.                       (named-let-expressions expr)))]))
  345.  
  346. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  347. ;; 10. ENVIRONMENT AND FRAMES  ;;
  348. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  349.  
  350. ;; An environment is a mutable list of frames.  The enclosing environment is the mcdr
  351. ;; of the list.  A frame is a mutable list of bindings with a 'frame header.  A
  352. ;; binding is a var-val pair ie (mcons var val).
  353.  
  354. ;; Environments support four procedures:
  355.     ;; lookup-variable-value
  356.     ;; extend-environment
  357.     ;; define-variable
  358.     ;; set-variable-value
  359.  
  360. ;; Two helper functions support the environment procedures:
  361.     ;; find-binding-in-frame
  362.     ;; find-binding-in-environment
  363.  
  364. (define (enclosing-environment env) (mcdr env))
  365. (define (first-frame env) (mcar env))
  366. (define the-empty-environment empty)
  367. (define the-empty-frame (mlist 'frame))
  368. (define (empty-frame? frame)
  369.   (empty? (frame-bindings frame)))
  370. (define (make-frame vars vals)
  371.   (mcons 'frame
  372.          (mmap mcons
  373.                (list->mlist vars)
  374.                (list->mlist vals))))
  375. (define (frame-bindings frame) (mcdr frame))
  376. (define (frame-variables frame) (mmap mcar (frame-bindings frame)))
  377. (define (frame-values frame) (mmap mcdr (frame-bindings frame)))
  378.  
  379. (define (binding-variable binding) (mcar binding))
  380. (define (binding-value binding) (mcdr binding))
  381. (define (set-value! binding val) (set-mcdr! binding val))
  382. (define (add-binding-to-frame! var val frame)
  383.   (mappend! frame (mlist (mcons var val))))
  384. (define (find-binding-in-frame var frame)
  385.   ; Return the var-val pair if present else false.
  386.   (define (loop bindings)
  387.     (cond [(empty? bindings) false]
  388.           [else
  389.             (define b (mcar bindings))
  390.             (if (eq? var (binding-variable b))
  391.               b
  392.               (loop (mcdr bindings)))]))
  393.   (loop (frame-bindings frame)))
  394. (define (find-binding-in-env var env)
  395.   ; Return the closest binding for var if present else false.
  396.   (cond [(eq? env the-empty-environment) false]
  397.         [else
  398.           (define b (find-binding-in-frame var (first-frame env)))
  399.           (or b (find-binding-in-env var (enclosing-environment env)))]))
  400.  
  401. (define (lookup-variable-value var env)
  402.   (define b (find-binding-in-env var env))
  403.   (if b
  404.     (binding-value b)
  405.     (error "Unbound variable" var)))
  406. (define (extend-environment vars vals base-env)
  407.   (cond [(= (length vars) (length vals))
  408.          (mcons (make-frame vars vals) base-env)]
  409.         [else
  410.           (if (< (length vars) (length vals))
  411.             (error "Too many arguments supplied" vars vals)
  412.             (error "Too few arguments supplied" vars vals))]))
  413. (define (define-variable! var val env)
  414.   (define frame (first-frame env))
  415.   (define b (find-binding-in-frame var frame))
  416.   (if b
  417.     (set-value! b val)
  418.     (add-binding-to-frame! var val frame)))
  419. (define (set-variable-value! var val env)
  420.   (define b (find-binding-in-env var env))
  421.   (if b
  422.     (set-value! b val)
  423.     (error "Unbound variable -- SET!" var)))
  424.  
  425. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  426. ;; 11. PRIMITIVE PROCEDURES AND THE GLOBAL ENVIRONMENT  ;;
  427. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  428.  
  429. (define primitive-procedures
  430.   (list
  431.     (list 'cons cons)
  432.     (list 'car car)
  433.     (list 'cdr cdr)
  434.     (list '+ +)
  435.     (list '* *)
  436.     (list '- -)
  437.     (list '< <)
  438.     (list '> >)
  439.     (list '<= <=)
  440.     (list '>= >=)
  441.     (list '= =)
  442.     (list 'not not)
  443.     (list 'false? false?)
  444.     (list 'true? (lambda (x) (not (false? x))))
  445.     (list 'empty? empty?)
  446.     ))
  447. (define (primitive-procedure? proc)
  448.   (tagged-list? proc 'primitive))
  449. (define (primitive-implementation proc)
  450.   (second proc))
  451. (define (primitive-procedure-names)
  452.   (map first primitive-procedures))
  453. (define (primitive-procedure-objects)
  454.   (map (lambda (proc) (list 'primitive (second proc)))
  455.        primitive-procedures))
  456. (define apply-in-underlying-scheme apply)
  457. ;; The metacircular evaluator's apply is my-apply.
  458. (define (apply-primitive-procedure proc args)
  459.   (apply-in-underlying-scheme
  460.     (primitive-implementation proc) args))
  461.  
  462. (define (setup-environment)
  463.   (define initial-env
  464.     (extend-environment (primitive-procedure-names)
  465.                         (primitive-procedure-objects)
  466.                         the-empty-environment))
  467.   (define-variable! 'true true initial-env)
  468.   (define-variable! 'false false initial-env)
  469.   initial-env)
  470. (define the-global-environment (setup-environment))
  471.  
  472. ;;;;;;;;;;;;;;;;;;;;;;;;;;
  473. ;; 12. REPL OPERATIONS  ;;
  474. ;;;;;;;;;;;;;;;;;;;;;;;;;;
  475.  
  476. (define input-prompt ";;; M-Eval input:")
  477. (define output-prompt ";;; M-Eval value:")
  478. (define (driver-loop)
  479.   (prompt-for-input input-prompt)
  480.   (let* ([input (read)]
  481.          [output (my-eval input the-global-environment)])
  482.     (announce-output output-prompt)
  483.     (user-print output))
  484.   (driver-loop))
  485. (define prompt-for-input displayln)
  486. (define announce-output displayln)
  487. (define (user-print object)
  488.   (if (compound-procedure? object)
  489.     (displayln (list 'compound-procedure
  490.                    (procedure-parameters object)
  491.                    (procedure-body object)
  492.                    '<procedure-env>))
  493.     (displayln object)))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement