implementation-00-mutation.scm 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. ;; WARNING: This implementation makes use of mutation. It uses the trick of
  2. ;; storing members in the environment of a returned closure and mutating these
  3. ;; members inside the closure.
  4. ;;; Queue obect
  5. ;; Implemented operations:
  6. ;; 'push x: push x onto the rear of the queue
  7. ;; 'pop: remove the head of the queue and return it
  8. ;; 'peek: return the head of the queue
  9. ;; 'show: show the queue's contents
  10. ;; 'fb: show the front and back parts of the queue (for debugging)
  11. (define make-queue
  12. ;; make-queue takes no arguments. the queue will be empty initially.
  13. (lambda ()
  14. ;; a queue is a procedure
  15. (let ((front '()) (back '()))
  16. ;; in this procedure front and back are 2 stacks which are bound in the
  17. ;; environment. the procedure takes 2 arguments: a desired operation and
  18. ;; the data on which to work on.
  19. (lambda (cmd . data)
  20. ;; ???
  21. (define exchange
  22. (lambda ()
  23. ;; WARNING: mutation here
  24. (set! front (reverse back))
  25. (set! back '())))
  26. (define pop
  27. (lambda (stack)
  28. (let ([res (car stack)])
  29. (set! front (cdr stack))
  30. res)))
  31. ;; match on cmd.
  32. (case cmd
  33. ;; We push new elements on top of the back stack, because they are
  34. ;; the ones we want to retrieve last (FIFO - first in first
  35. ;; out). When the front stack is empty, the back stack will be
  36. ;; reversed and thus the last pushed element will be the one at the
  37. ;; bottom of the stack, making it the last one we will pop.
  38. [(push)
  39. (set! back (cons (car data) back))]
  40. [(pop)
  41. (cond
  42. [(null? front)
  43. (exchange)
  44. (pop front)]
  45. [else
  46. (pop front)])]
  47. ;; If we are trying to access the head of the queue, but there is no
  48. ;; element stored in the front stack, perform the exchange operation
  49. ;; and only then return the head of the mutated front stack. If there
  50. ;; is an element at the head of the front stack in the first place,
  51. ;; return that instead.
  52. [(peek)
  53. (unless (pair? front)
  54. (exchange))
  55. (car front)]
  56. ;; show is displaying the queue's contents
  57. [(show)
  58. (display
  59. (simple-format
  60. #f "~s\n"
  61. (append front (reverse back))))]
  62. ;; fb = front / back
  63. [(fb)
  64. (display
  65. (simple-format
  66. #f "front: ~s, back: ~s\n"
  67. front back))]
  68. ;; Otherwise signal an error.
  69. [else
  70. (error "Illegal cmd to queue object" cmd)])))))