;; Here's a simple program for incrementing a counter

(define count 0)

;; incr-count : -> number
;; increments count and returns the new count value
(define incr-count
  (lambda ()
    (begin
      (set! count (+ count 1))
      count)))

;; -------------------------------------------------------------------

;; Let's try to hide the count variable so that it can't
;; be modified outside of the incr program:

;; incr-count/safe1 : -> number
;; increments count and returns the new count value
(define incr-count/safe1
  (lambda ()
    (local [(define count 0)]
      (begin
        (set! count (+ count 1))
        count))))

;; This version doesn't work though, because count gets redefined
;; every time we call incr-count.

;; -------------------------------------------------------------------

;; This version works because the count is defined outside of the lambda

;; incr-count/safe2 : -> number
;; increments count and returns the new count value
(define incr-count/safe2
  (local [(define count 0)]
    (lambda ()
      (begin
        (set! count (+ count 1))
        count))))

;; -------------------------------------------------------------------

;; We want to move towards being able to add new services to our counter.
;; As a first step, let's give a name to the current function body

;; incr-count/safe3 : -> number
;; increments count and returns the new count value
(define incr-count/safe3
  (local [(define count 0)
          ;; incr-count : -> number
          ;; increments count and returns the new count value
          (define incr-count
            (lambda ()
              (begin
                (set! count (+ count 1))
                count)))]
    (lambda ()
      (incr-count))))

;; -------------------------------------------------------------------

;; Now, add a reset-counter service and the code to dispatch according to 
;; the requested service

;; counter : symbol -> number
;; updates and returns new value of a counter based on requested service
(define counter
  (local [(define count 0)
          ;; incr-count : -> number
          ;; increments count and returns the new count value
          (define incr-count
            (lambda ()
              (begin
                (set! count (+ count 1))
                count)))
           ;; reset-count : -> number
           ;; sets count value to 0 and returns 0
          (define reset-count
            (lambda ()
              (begin
                (set! count 0)
                count)))]
    (lambda (service)
      (cond [(symbol=? service 'incr) (incr-count)]
            [(symbol=? service 'reset) (reset-count)]))))

