Advertisement
timothy235

sicp-4-1-2-representing-expressions

Mar 11th, 2017
137
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Racket 13.01 KB | None | 0 0
  1. #lang racket
  2.  
  3. ;; This will not run due to undefined terms.
  4.  
  5. ;;;;;;;;;
  6. ;; 4.2 ;;
  7. ;;;;;;;;;
  8.  
  9. ;; a.  Since the predicate for recognizing procedure applications was 'any compound
  10. ;; expression not already parsed', the repl will mistake any compound expression with
  11. ;; a lower clause as a procedure application.  For example, upon encountering
  12. ;; (define x 3), the repl will search the environment for a procedure named define.
  13.  
  14. ;; b.  The predicate and selectors for procedure applications must change to:
  15.  
  16. (define (application? expr) (tagged-list? expr 'call))
  17. (define (operator expr) (second expr))
  18. (define (operands expr) (rest (rest expr)))
  19.  
  20. ;;;;;;;;;
  21. ;; 4.3 ;;
  22. ;;;;;;;;;
  23.  
  24. ;; Assume we have all the selectors and constructors, as in the book.
  25. ;; Assume also that procedure applications are tagged lists beginning with 'call.
  26. ;; Then the data-directed version of my-eval looks like this:
  27.  
  28. (define eval-table (make-hash))
  29. (define (put type item) (hash-set! eval-table type item))
  30. (define (get type) (hash-ref eval-table type))
  31.  
  32. (define (type expr)
  33.   (and (pair? expr)
  34.        (symbol? (first expr))
  35.        (first expr)))
  36.  
  37. (define (my-eval expr env) ; data-directed style
  38.   (cond [(self-evaluating? expr) expr]
  39.         [(variable? expr) (lookup-variable-value expr env)]
  40.         [else ((get (type expr)) expr env)]))
  41.  
  42. (define (install-evaluation-rules)
  43.   (define (quote-rule expr env)
  44.     (text-of-quotation expr))
  45.   (define (assignment-rule expr env)
  46.     (eval-assignment expr env))
  47.   (define (definition-rule expr env)
  48.     (eval-definition expr env))
  49.   (define (lambda-rule expr env)
  50.     (make-procedure (lambda-parameters expr)
  51.                     (lambda-body expr)
  52.                     env))
  53.   (define (conditional-rule expr env)
  54.     (eval-if expr env))
  55.   (define (begin-rule expr env)
  56.     (eval-sequence (begin-actions expr) env))
  57.   (define (application-rule expr env)
  58.     (my-apply (my-eval (operator expr) env)
  59.               (list-of-values (operands expr) env)))
  60.   (define (cond-rule expr env)
  61.     (my-eval (cond->if expr) env))
  62.   (put 'quote quote-rule)
  63.   (put 'set! assignment-rule)
  64.   (put 'define definition-rule)
  65.   (put 'lambda lambda-rule)
  66.   (put 'if conditional-rule)
  67.   (put 'begin begin-rule)
  68.   (put 'call application-rule)
  69.   (put 'cond cond-rule)
  70.   )
  71.  
  72. ;;;;;;;;;
  73. ;; 4.4 ;;
  74. ;;;;;;;;;
  75.  
  76. ;; AND
  77.  
  78. ;; Add this clause to my-eval:
  79.     [(and? expr) (eval-and expr env)]
  80.  
  81. (define (and? expr) (tagged-list? expr 'and))
  82. (define (and-operands expr) (rest expr))
  83. (define (make-and sequence) (cons 'and sequence))
  84. (define (eval-and expr env)
  85.   (define ops (and-operands expr))
  86.   (cond [(empty? ops) 'true] ; (and) should be true
  87.         [else
  88.           (define val (my-eval (first ops) env))
  89.           (define rest-ops (rest ops))
  90.           (cond [(empty? rest-ops) val] ; (and x) should be x
  91.                 [(eq? val 'false) 'false]
  92.                 [else
  93.                   (eval-and (make-and rest-ops) env)])]))
  94.  
  95. ;; OR
  96.  
  97. ;; Add this clause to my-eval:
  98.     [(or? expr) (eval-or expr env)]
  99.  
  100. (define (or? expr) (tagged-list? expr 'or))
  101. (define (or-operands expr) (rest expr))
  102. (define (make-or sequence) (cons 'or sequence))
  103. (define (eval-or expr env)
  104.   (define ops (or-operands expr))
  105.   (cond [(empty? ops) 'false] ; (or) should be false
  106.         [else
  107.           (define val (my-eval (first ops) env))
  108.           (define rest-ops (rest first-ops))
  109.           (cond [(empty? rest-ops) val] ; (or x) should be x
  110.                 [(not (eq? val 'false)) val]
  111.                 [else
  112.                   (eval-or (make-or rest-ops) env)])]))
  113.  
  114. ;; AND AS A DERIVED EXPRESSION
  115.  
  116. (define (and->if expr)
  117.   (expand-and-operands (and-operands expr)))
  118. (define (expand-and-operands ops)
  119.   (cond [(empty? ops) 'true]
  120.         [else
  121.           (define first-op (first ops))
  122.           (define rest-ops (rest ops))
  123.           (cond [(empty? rest-ops) first-op]
  124.                 [else
  125.                   (make-if first-op
  126.                            (and->if (make-and rest-ops))
  127.                            'false)])]))
  128.  
  129. ;; test
  130.  
  131. (and->if '(and x1 x2 x3))
  132. ;; '(if x1 (if x2 x3 false) false)
  133.  
  134. ;; OR AS A DERIVED EXPRESSION
  135.  
  136. (define (or->if expr)
  137.   (expand-or-operands (or-operands expr)))
  138. (define (expand-or-operands ops)
  139.   (cond [(empty? ops) 'false] ; (or) should return false
  140.         [else
  141.           (define first-op (first ops))
  142.           (define rest-ops (rest ops))
  143.           (cond [(empty? rest-ops) first-op] ; (or x) should return x
  144.                 [else
  145.                   (make-if first-op
  146.                            first-op ; inefficient second evaluation
  147.                            (or->if (make-or rest-ops)))])]))
  148.  
  149. ;; test
  150.  
  151. (or->if '(or y1 y2 y3))
  152. ;; '(if y1 y1 (if y2 y2 y3))
  153.  
  154. ;; OR AS A DERIVED EXPRESSION, WITH ACCESS TO THE ENVIRONMENT
  155.  
  156. (define (or->if2 expr env)
  157.   (expand-or-operands2 (or-operands expr) env))
  158. (define (expand-or-operands2 ops env)
  159.   (cond [(empty? ops) 'false]
  160.         [else
  161.           (define val (my-eval (first ops) env))
  162.           (define rest-ops (rest ops))
  163.           (cond [(empty? rest-ops) val]
  164.                 [else
  165.                   (make-if val ; no inefficient second evaluation
  166.                            val
  167.                            (or->if2 (make-or rest-ops)))])]))
  168.  
  169. ;;;;;;;;;
  170. ;; 4.5 ;;
  171. ;;;;;;;;;
  172.  
  173. (define (cond? expr) (tagged-list? expr 'cond))
  174. (define (cond-clauses expr) (rest expr))
  175. ; regular cond clause
  176. (define (cond-predicate clause) (first clause))
  177. (define (cond-actions clause) (rest clause))
  178. ; alternate test clause
  179. (define (cond-alternate-clause? clause)
  180.   (eq? (second clause) '=>))
  181. (define (cond-test clause) (first clause))
  182. (define (cond-recipient clause) (third clause))
  183. ; else clause
  184. (define (cond-else-clause? clause)
  185.   (eq? (cond-predicate clause) 'else))
  186. ; derive cond from if, needs access to the environment
  187. (define (cond->if expr)
  188.   (expand-clauses (cond-clauses expr)))
  189. (define (expand-clauses clauses)
  190.   (cond [(empty? clauses) 'false] ; no else clause
  191.         [else
  192.           (define first-clause (first clauses))
  193.           (define rest-clauses (rest clauses))
  194.           (cond [(cond-else-clause? first-clause)
  195.                  (if (empty? rest-clauses)
  196.                    (sequence->exp (cond-actions first-clause))
  197.                    (error "ELSE clause isn't last -- COND->IF" clauses))]
  198.                 [(cond-alternate-clause? first-clause)
  199.                  (define test (cond-test first-clause))
  200.                  (define recipient (cond-recipient first-clause))
  201.                  (make-if test
  202.                           (list recipient test)
  203.                           (expand-clauses rest-clauses))]
  204.                 [else
  205.                   (make-if (cond-predicate first-clause)
  206.                            (sequence->exp (cond-actions first-clause))
  207.                            (expand-clauses rest-clauses))])]))
  208.  
  209. ;; tests
  210.  
  211. (cond->if '(cond [a 1] [b 2] [else 3]))
  212. ;; '(if a 1 (if b 2 3))
  213.  
  214. (cond->if '(cond [a 1] [(list 1 2) => car] [else 3]))
  215. ;; '(if a 1 (if (list 1 2) (car (list 1 2)) 3))
  216.  
  217. ;;;;;;;;;
  218. ;; 4.6 ;;
  219. ;;;;;;;;;
  220.  
  221. ;; Add this clause to my-eval:
  222.     [(let? expr) (my-eval (let->combination expr) env)]
  223.  
  224. (define (let? expr) (tagged-list? expr 'let))
  225. (define (let-bindings expr) (second expr))
  226. (define (let-parameters expr) (map first (let-bindings expr)))
  227. (define (let-expressions expr) (map second (let-bindings expr)))
  228. (define (let-body expr)
  229.   (sequence->exp (rest (rest expr))))
  230. (define (let->combination expr)
  231.   (cond [(empty? (let-bindings expr)) ; do not unnecessarily lambda wrap
  232.          (let-body expr)]
  233.         [else
  234.           (cons (make-lambda (let-parameters expr)
  235.                              (let-body expr))
  236.                 (let-expressions expr))]))
  237. (define (make-let bindings body)
  238.   (cons 'let (list bindings body)))
  239.  
  240. ;; test
  241.  
  242. (let->combination '(let () (+ 1 2)))
  243. ;; '(+ 1 2)
  244.  
  245. (let->combination '(let ((a 1) (b 2)) (+ a b)))
  246. ;; '((lambda (a b) (+ a b)) 1 2)
  247.  
  248. ;;;;;;;;;
  249. ;; 4.7 ;;
  250. ;;;;;;;;;
  251.  
  252. ;; I think it's fine to implement let* as a derived form.  my-eval will have to be
  253. ;; called recursively to evaluate the inner let's, but that's fine, my-eval is meant
  254. ;; to be recursive.
  255.  
  256. ;; Add this clause to my-eval:
  257.     [(let*? expr) (my-eval (let*->nested-lets expr) env)]
  258.  
  259. (define (let*? expr) (tagged-list? expr 'let*))
  260. (define (let*-bindings expr) (second expr))
  261. (define (let*-body expr)
  262.   (sequence->exp (rest (rest (expr)))))
  263. (define (make-let* bindings body)
  264.   (cons 'let* (list bindings body)))
  265.  
  266. (define (let*->nested-lets expr)
  267.   (define bindings (let*-bindings expr))
  268.   (cond [(empty? bindings)
  269.          (let-body expr)]
  270.         [else
  271.           (make-let
  272.             (list (first bindings))
  273.             (let*->nested-lets
  274.               (make-let* (rest bindings)
  275.                          (let-body expr))))]))
  276.  
  277. ;; test
  278.  
  279. (let*->nested-lets '(let* () (+ 1 2)))
  280. ;; '(+ 1 2)
  281.  
  282. (let*->nested-lets '(let* ((a 1) (b (+ a 1))) (+ a b)))
  283. ;; '(let ((a 1)) (let ((b (+ a 1))) (+ a b)))
  284.  
  285. (let->combination (let*->nested-lets '(let* ((a 1) (b (+ a 1))) (+ a b))))
  286. ;; '((lambda (a) (let ((b (+ a 1))) (+ a b))) 1)
  287.  
  288. ;;;;;;;;;
  289. ;; 4.8 ;;
  290. ;;;;;;;;;
  291.  
  292. ;; Add this clause to my-eval:
  293.     [(named-let? expr) (my-eval (named-let->sequence expr) env)]
  294.  
  295. (define (named-let? expr)
  296.   (and (let? expr)
  297.        (not (list? (second expr)))))
  298. (define (named-let-name expr) (second expr))
  299. (define (named-let-bindings expr) (third expr))
  300. (define (named-let-parameters expr) (map first (named-let-bindings expr)))
  301. (define (named-let-expressions expr) (map second (named-let-bindings expr)))
  302. (define (named-let-body expr)
  303.   (sequence->exp (rest (rest (rest expr)))))
  304.  
  305. ;; At first I tried converting the named let to a regular let by adding the name-body
  306. ;; pair as a new let-binding, but that did not work.
  307.  
  308. ;; For example, my original wrong named-let->sequence took the expression below,
  309. ;; which, when unquoted, evaluates to (fib 10) = 55;  and produced an expression
  310. ;; that, when unquoted, produced a 'fib-iter undefined' error:
  311.  
  312. '(let fib-iter ((a 1)
  313.                 (b 0)
  314.                 (count 10))
  315.    (if (zero? count)
  316.      b
  317.      (fib-iter (+ a b) a (sub1 count))))
  318. ;; '((lambda (fib-iter a b count)
  319.     ;; (if (zero? count) b (fib-iter (+ a b) a (sub1 count))))
  320.   ;; (lambda (a b count) (if (zero? count) b (fib-iter (+ a b) a (sub1 count))))
  321.   ;; 1
  322.   ;; 0
  323.   ;; 10)
  324.  
  325. ((lambda (fib-iter a b count)
  326.    (if (zero? count) b (fib-iter (+ a b) a (sub1 count))))
  327.  (lambda (a b count) (if (zero? count) b (fib-iter (+ a b) a (sub1 count))))
  328.  1
  329.  0
  330.  10)
  331. ;; . . fib-iter: undefined;
  332.  ;; cannot reference undefined identifier
  333.  
  334. ;; So this version of named-let->sequence creates a sequence of two expressions,
  335. ;; one to define the named function, and the second to apply it to the named-let
  336. ;; expressions.
  337.  
  338. (define (named-let->sequence expr)
  339.   (define bindings (named-let-bindings expr))
  340.   (cond [(empty? bindings)
  341.          (named-let-body expr)]
  342.         [else
  343.           (list 'begin
  344.                 (list 'define ; first define the named function
  345.                       (cons (named-let-name expr)
  346.                             (named-let-parameters expr))
  347.                       (named-let-body expr))
  348.                 (cons (named-let-name expr) ; then apply it to the expressions
  349.                       (named-let-expressions expr)))]))
  350.  
  351. ;; test
  352.  
  353. (named-let->sequence '(let f () (+ 1 2)))
  354. ;; '(+ 1 2)
  355.  
  356. (named-let->sequence
  357.   '(let fib-iter ((a 1)
  358.                   (b 0)
  359.                   (count 10))
  360.      (if (zero? count)
  361.        b
  362.        (fib-iter (+ a b) a (sub1 count)))))
  363. ;; '(begin
  364.    ;; (define (fib-iter a b count)
  365.      ;; (if (zero? count) b (fib-iter (+ a b) a (sub1 count))))
  366.    ;; (fib-iter 1 0 10))
  367.  
  368. (begin
  369.   (define (fib-iter a b count)
  370.     (if (zero? count) b (fib-iter (+ a b) a (sub1 count))))
  371.   (fib-iter 1 0 10))
  372. ;; 55
  373.  
  374. ;;;;;;;;;
  375. ;; 4.9 ;;
  376. ;;;;;;;;;
  377.  
  378. ;; THE WHILE LOOP
  379.  
  380. '(while <test> do <body>)
  381.  
  382. ;; is a derived form for:
  383.  
  384. '(if <test>
  385.    (begin <body>
  386.           (while <test> do <body>))
  387.    done)
  388.  
  389. ;; Add this clause to my-eval:
  390.     [(while? expr) (my-eval (while->if expr) env)]
  391.  
  392. (define (while? expr) (tagged-list? expr 'while))
  393. (define (while-test expr) (second expr))
  394. (define (while-body expr) (fourth expr))
  395. (define (make-while test body) (list 'while test 'do body))
  396. (define (while->if expr)
  397.   (make-if (while-test expr)
  398.            (list 'begin
  399.                  (while-body expr)
  400.                  (make-while (while-test expr)
  401.                              (while-body expr)))
  402.            'done))
  403.  
  404. ;; test
  405.  
  406. (while->if '(while (positive? x) do (begin (log! x) (set! x (sub1 x)))))
  407. ;; '(if (positive? x)
  408.    ;; (begin
  409.      ;; (begin (log! x) (set! x (sub1 x)))
  410.      ;; (while (positive? x) do (begin (log! x) (set! x (sub1 x)))))
  411.    ;; done)
  412.  
  413. ;;;;;;;;;;
  414. ;; 4.10 ;;
  415. ;;;;;;;;;;
  416.  
  417. ;; For example we could change the syntax for assignment from:
  418.  
  419. (set! <var> <value>)
  420.  
  421. ;; to:
  422.  
  423. (set! <value> <var>)
  424.  
  425. ;; simply by changing the following procedures:
  426.  
  427. (define (assignment-variable expr) (third expr))
  428. (define (assignment-value expr) (second expr))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement