Advertisement
timothy235

sicp-4-1-3-evaluator-data-structures

Mar 12th, 2017
181
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Racket 7.28 KB | None | 0 0
  1. #lang racket
  2. (require racket/mpair)
  3.  
  4. ;;;;;;;;;;
  5. ;; 4.11 ;;
  6. ;;;;;;;;;;
  7.  
  8. ;; A frame is a list of name-value pairs with a 'frame header.  Note that we can't
  9. ;; use the empty list for the empty frame; otherwise, the empty frame would have no
  10. ;; mcar or mcdr to mutate when we want to add a binding.  Hence the 'frame header.
  11.  
  12. (define the-empty-frame (mlist 'frame))
  13. (define (empty-frame? frame)
  14.   (empty? (frame-bindings frame)))
  15.  
  16. (define (make-frame vars vals)
  17.   (mcons 'frame (mmap mcons vars vals)))
  18. (define (frame-bindings frame) (mcdr frame))
  19. (define (frame-variables frame) (mmap mcar (frame-bindings frame)))
  20. (define (frame-values frame) (mmap mcdr (frame-bindings frame)))
  21.  
  22. (define (binding-variable binding) (mcar binding))
  23. (define (binding-value binding) (mcdr binding))
  24. (define (set-value! binding val) (set-mcdr! binding val))
  25.  
  26. (define (add-binding-to-frame! var val frame)
  27.   (mappend! frame (mlist (mcons var val))))
  28.  
  29. ;; TESTS FOR ADD-BINDING-TO-FRAME!
  30.  
  31. (define frame1 (make-frame (mlist 'a) (mlist 1)))
  32. (add-binding-to-frame! 'b 2 frame1)
  33. ;; (mcons 'frame (mcons (mcons 'a 1) (mcons (mcons 'b 2) '())))
  34. (equal? frame1 (make-frame (mlist 'a 'b) (mlist 1 2)))
  35. ;; #t
  36.  
  37. (define frame2 the-empty-frame)
  38. (add-binding-to-frame! 'a 1 frame2)
  39. ;; (mcons 'frame (mcons (mcons 'a 1) '()))
  40. (equal? frame2 (make-frame (mlist 'a) (mlist 1)))
  41. ;; #t
  42.  
  43. ;; We also need to change set-variable-value! and define-variable!.
  44. ;; lookup-variable-value is OK as written for the new frame representation.
  45.  
  46. (define (find-binding-in-frame var frame)
  47.   ; Return the var-val pair if present else false.
  48.   (define (loop bindings)
  49.     (cond [(empty? bindings) false]
  50.           [else
  51.             (define b (mcar bindings))
  52.             (if (eq? var (binding-variable b))
  53.               b
  54.               (loop (mcdr bindings)))]))
  55.   (loop (frame-bindings frame)))
  56.  
  57. (define (set-variable-value! var val env)
  58.   (define (env-loop env)
  59.     (cond [(eq? env the-empty-environment)
  60.            (error "Unbound variable -- SET!" var)]
  61.           [else
  62.             (define frame (first-frame env))
  63.             (define b (find-binding-in-frame var frame))
  64.             (if b
  65.               (set-value! b val)
  66.               (env-loop (enclosing-environment env)))]))
  67.   (env-loop env))
  68.  
  69. (define (define-variable! var val env)
  70.   (define frame (first-frame env))
  71.   (define b (find-binding-in-frame var frame))
  72.   (if b
  73.     (set-mcar! b val)
  74.     (add-binding-to-frame! var val frame)))
  75.  
  76. (define (lookup-variable-value var env) ; this is the book version
  77.   (define (env-loop env)
  78.     (define (scan vars vals)
  79.       (cond [(empty? vars)
  80.              (env-loop (enclosing-environment env))]
  81.             [(eq? var (mcar vars))
  82.              (mcar vals)]
  83.             [else (scan (mcdr vars) (mcdr vals))]))
  84.     (cond [(eq? env the-empty-environment)
  85.            (error "Unbound variable" var)]
  86.           [else
  87.             (define frame (first-frame env))
  88.             (scan (frame-variables frame)
  89.                   (frame-values frame))]))
  90.   (env-loop env))
  91.  
  92. (define (enclosing-environment env) (mcdr env))
  93. (define (first-frame env) (mcar env))
  94. (define the-empty-environment empty)
  95.  
  96. ;; TEST
  97.  
  98. (define f (make-frame (mlist 'a 'b 'c) (mlist 1 2 3)))
  99. (define env (mlist f))
  100.  
  101. (lookup-variable-value 'c env)
  102. ;; 3
  103. (set-variable-value! 'c 42 env)
  104. (lookup-variable-value 'c env)
  105. ;; 42
  106. (define-variable! 'd 5 env) ; mappend! in add-binding-to-frame! returns the frame
  107. ;; (mcons
  108.  ;; 'frame
  109.  ;; (mcons
  110.   ;; (mcons 'a 1)
  111.   ;; (mcons (mcons 'b 2) (mcons (mcons 'c 42) (mcons (mcons 'd 5) '())))))
  112. (lookup-variable-value 'd env)
  113. ;; 5
  114. env
  115. ;; (mcons
  116.  ;; (mcons
  117.   ;; 'frame
  118.   ;; (mcons
  119.    ;; (mcons 'a 1)
  120.    ;; (mcons (mcons 'b 2) (mcons (mcons 'c 42) (mcons (mcons 'd 5) '())))))
  121.  ;; '())
  122.  
  123. ;;;;;;;;;;
  124. ;; 4.12 ;;
  125. ;;;;;;;;;;
  126.  
  127. ;; We can abstract these procedures in terms of find-binding-in-frame and a new
  128. ;; procedure find-binding-in-env.  We'll keep the frame representation from exercise
  129. ;; 4.11.
  130.  
  131. (define (find-binding-in-env var env)
  132.   ; Return the closest binding for var if present else false.
  133.   (cond [(eq? env the-empty-environment) false]
  134.         [else
  135.           (define b (find-binding-in-frame var (first-frame env)))
  136.           (or b (find-binding-in-env var (enclosing-environment env)))]))
  137.  
  138. (define (lookup-variable-value2 var env)
  139.   (define b (find-binding-in-env var env))
  140.   (if b
  141.     (binding-value b)
  142.     (error "Unbound variable" var)))
  143.  
  144. (define (set-variable-value2! var val env)
  145.   (define b (find-binding-in-env var env))
  146.   (if b
  147.     (set-value! b val)
  148.     (error "Unbound variable -- SET!" var)))
  149.  
  150. (define (define-variable2! var val env)
  151.   (define frame (first-frame env))
  152.   (define b (find-binding-in-frame var frame))
  153.   (if b
  154.     (set-value! b val)
  155.     (add-binding-to-frame! var val frame)))
  156.  
  157. ;; TEST
  158.  
  159. (define f2 (make-frame (mlist 'x 'y 'z) (mlist 10 11 12)))
  160. (define env2 (mlist f2))
  161.  
  162. (lookup-variable-value2 'y env2)
  163. ;; 11
  164. (set-variable-value2! 'y 42 env2)
  165. (lookup-variable-value2 'y env2)
  166. ;; 42
  167. (define-variable2! 'w 33 env2) ; mappend! in add-binding-to-frame! returns the frame
  168. ;; (mcons
  169.  ;; 'frame
  170.  ;; (mcons
  171.   ;; (mcons 'x 10)
  172.   ;; (mcons (mcons 'y 42) (mcons (mcons 'z 12) (mcons (mcons 'w 33) '())))))
  173. (lookup-variable-value2 'w env2)
  174. ;; 33
  175. env2
  176. ;; (mcons
  177.  ;; (mcons
  178.   ;; 'frame
  179.   ;; (mcons
  180.    ;; (mcons 'x 10)
  181.    ;; (mcons (mcons 'y 42) (mcons (mcons 'z 12) (mcons (mcons 'w 33) '())))))
  182.  ;; '())
  183. ;; (lookup-variable-value2 'not-there env2)
  184. ;; ;; . . Unbound variable not-there
  185.  
  186. ;;;;;;;;;;
  187. ;; 4.13 ;;
  188. ;;;;;;;;;;
  189.  
  190. ;; We'll have make-unbound! remove only the binding in the first frame.  In the
  191. ;; interest of modularity, it seems unwise to have a procedure that searches and
  192. ;; modifies the entire environment, possibly removing bindings created by other parts
  193. ;; of the program.  But if we ever needed that functionality, we could always create
  194. ;; a make-global-unbound! function.
  195.  
  196. ;; Should we remove frames from the environment that have had all the bindings
  197. ;; removed?  I think not because the frame is a node in a graph, a place, and not
  198. ;; just a collection of values.  A procedure may want to create new bindings in that
  199. ;; place without realizing it is empty and needs to be created.  So be aware that
  200. ;; this implementation of make-unbound! may leave empty frames in the environment.
  201.  
  202. ;; Use the representaion and helper functions from exercises 4.11 and 4.12.
  203.  
  204. (define (remove-binding! b frame)
  205.   ; Mutate frame to remove b.  Assume b is in frame.
  206.   (define (loop! lst)
  207.     (if (equal? b (mcar (mcdr lst)))
  208.       (set-mcdr! lst (mcdr (mcdr lst)))
  209.       (loop! (mcdr lst))))
  210.   (loop! frame))
  211.  
  212. (define (make-unbound! var env)
  213.   (define frame (first-frame env))
  214.   (define b (find-binding-in-frame var frame))
  215.   (when b (remove-binding! b frame)))
  216.  
  217. ;; TEST
  218.  
  219. (define f3 (make-frame (mlist 'p 'q 'r) (mlist 1 2 3)))
  220. (define env3 (mlist f3))
  221. env3
  222. ;; (mcons
  223.  ;; (mcons
  224.   ;; 'frame
  225.   ;; (mcons (mcons 'p 1) (mcons (mcons 'q 2) (mcons (mcons 'r 3) '()))))
  226.  ;; '())
  227. (make-unbound! 'p env3)
  228. env3
  229. ;; (mcons (mcons 'frame (mcons (mcons 'q 2) (mcons (mcons 'r 3) '()))) '())
  230. (make-unbound! 'r env3)
  231. env3
  232. ;; (mcons (mcons 'frame (mcons (mcons 'q 2) '())) '())
  233. (make-unbound! 'q env3)
  234. env3
  235. ;; (mcons (mcons 'frame '()) '())
  236. (eq? env3 the-empty-environment)
  237. ;; #f
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement