;; Imperative Programming:  Modifying State.

;;
;; Exercise 2.26
;;

;; Since vectors are mutable, we use a one-element vector to
;; store the reference value.

(define-datatype reference reference?
  (a-ref
   (position integer?)
   (vec vector?)))

;; Cell interface operatios:  cell, cell?, contents, setcell

(define cell
  (lambda (value)
    (a-ref 0 (vector value))))

(define cell? reference?)

(define contents
  (lambda (c)
    (cases reference c
	   (a-ref (pos vec)
		  (vector-ref vec pos)))))

(define setcell
  (lambda (c newvalue)
    (cases reference c
	   (a-ref (pos vec)
		  (vector-set! vec pos newvalue)))))
	
;; e.g.:

(let ((c1 (cell 5)) (c2 (cell 10)))
    (begin
      (setcell c2 (+ (contents c1) (contents c2)))
      (setcell c1 (contents c2))
      (contents c1)))

(cell? (cell 0))

;;
;; An object-based version of the cell data type.
;;

(define cell
  (lambda (value)
    (let ((ref (a-ref 0 (vector value))))
      (letrec
	  ((cell?
	    (lambda () #t))
	   (contents
	    (lambda ()
	      (cases reference ref
		     (a-ref (pos vec)
			    (vector-ref vec pos)))))
	   (setcell
	    (lambda (newval)
	      (cases reference ref
		     (a-ref (pos vec)
			    (vector-set! vec pos newval))))))
	(vector cell? contents setcell)))))

(define cell-get-cell?-operation
  (lambda (c) (vector-ref c 0)))

(define cell-get-contents-operation
  (lambda (c) (vector-ref c 1)))

(define cell-get-setcell-operation
  (lambda (c) (vector-ref c 2)))

;; e.g.:

(let ((c1 (cell 5)) (c2 (cell 10)))
  (let ((get1 (cell-get-contents-operation c1))
	(get2 (cell-get-contents-operation c2))
	(set1 (cell-get-setcell-operation c1))
	(set2 (cell-get-setcell-operation c2)))
    (begin
      (set2 (+ (get1) (get2)))
      (set1 (get2))
      (get1))))

((cell-get-cell?-operation (cell 0)))

;; Exercise: add a get-set-cell operation that gets the current value
;; of the cell and then replaces it for a given new value.

;;
;; Examples of section 3.7
;;

(load "3-7.scm")

(run
"
  let x = 0
  in letrec even() = if zero?(x) then 1 
                                 else let d = set x = sub1(x)
                                      in (odd)
            odd()  = if zero?(x) then 0 
                                 else let d = set x = sub1(x)
                                      in (even)
     in let d = set x = 13 in (odd)
")

(run
"
  let g = let count = 0 
          in proc() 
               let d = set count = add1(count)
               in count
  in +((g), (g))
")

(run
"
  let x = 100
  in let inc = proc (x) 
                   let d = set x = add1(x)
                   in x
      in +((inc x), (inc x))
")

;; as opposed to:

(run
"
  let x = 100
  in let inc = proc () 
                   let d = set x = add1(x)
                   in x
      in +((inc), (inc))
")

;; Do exercise 3.39, so we do not need to use a 
;; dummy variable "d" for sequencing and we could
;; write instead:

(run
"
  let x = 0
  in letrec even() = if zero?(x) then 1 
                                 else begin 
                                        set x = sub1(x);
                                        (odd)
                                      end
            odd()  = if zero?(x) then 0 
                                 else begin
                                        set x = sub1(x);
                                        (even)
                                      end
     in begin
          set x = 13;
          (odd)
        end
")

;; Try out exercises 3.41, and 3.43.
