#lang racket

(define count 0)

;; (counter 'increment!)
(define (counter cmd)
  (case cmd
    [(increment!) (set! count (+ 1 count))]
    [(zero!) (set! count 0)])
  count)

;; (counter1 'increment!)
(define counter1
  (let ((count 0))
    (lambda (cmd)
      (case cmd
	[(increment!) (set! count (+ 1 count))]
	[(zero!) (set! count 0)])
      count)))

;; (not-a-counter 'increment!)
(define not-a-counter
  (lambda (cmd)
    (let ((count 0))
      (case cmd
	[(increment!) (set! count (+ 1 count)) count]
	[(zero!) (set! count 0) count]))))


;; (counter2 'increment!)
(define counter2
  (let ((count 0))
    (lambda cmd
      (if (null? cmd)
	  count
	  (begin
	    (case (car cmd)
	      [(increment!) (set! count (+ 1 count))]
	      [(zero!) (set! count 0)])
	    count)))))

;; (define c1 (make-counter 0))
;; (c1 'value)
;; (c1 'increment!)
(define make-counter
  (lambda (count)
    (lambda (command)
      (case command
	((zero!) (set! count 0) count)
	((increment!) (set! count (+ 1 count)) count)
	((value) count)
	(else 'error)))))


;; answer to sample final exam problem
(define (make-set name)
  (let ((lst '()))
    (lambda (cmd . args)
      (case cmd
	((name) name)
	((contains?)
	 (if (member (first args) lst)
	     #t
	     #f))
	((include)
	 (set! lst (cons (first args) lst))
	 'ok)))))
