;; Got into contexts and escapers by thinking about exceptions.  Go back and write our
;; exceptions examples using let/cc

#| original version
 
(define (check-div3 n d)
  (cond [(= d 0) (raise 'div-zero-exn)]
        [else (/ n d)]))

(with-handlers ([(lambda (exn) (symbol=? exn 'div-zero-exn))
                 (lambda (exn) "Oops --  divided by zero")])
  (check-div3 4 0))

|#

;; implement with-handlers manually using let/cc
(define (check-div3 n d div-zero-exn)
  (cond [(= d 0) (div-zero-exn "Oops -- divided by zero")]
        [else (/ n d)]))

(let/cc div-zero-exn
  (check-div3 4 0 div-zero-exn))

;; another version that defines how to handle the exn at the handler point, not the code

(define (check-div3a n d div-zero-exn-handler)
  (cond [(= d 0) (div-zero-exn-handler)]
        [else (/ n d)]))

(let/cc div-zero-exn-point 
  (let ([div-zero-exn-handler (lambda () (div-zero-exn-point "Oops -- divided by zero (version 3a)"))])
    (check-div3a 4 0 div-zero-exn-handler)))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; The expanded version

(define (check-div-nonzero d div-zero-exn-handler)
  (if (= d 0) (div-zero-exn-handler)))

(define (check-div4 n d div-zero-exn-handler)
  (begin
    (check-div-nonzero d div-zero-exn-handler)
    (/ n d)))

;; Also rewrite the two applications from last week:
;; in general, replace with-handlers with let/cc expressions and raises with calls to escapers

#|
;; something went wrong, let the user correct the problem
(define (div n)
  (printf "Enter a denominator: ")
  (let ([d (read)])
    (with-handlers ([(lambda (exn) (symbol=? exn 'div-zero-exn))
                     (lambda (exn) 
                       (printf "You tried to divide by zero.  Try again.~n")
                       (div n))])
      (check-div4 n d))))
|#

(define (div n)
  (printf "Enter a denominator: ")
  (let ([d (read)])
    (let/cc div-zero-exn-point
      (let ([div-zero-exn-handler
             (lambda ()
               (div-zero-exn-point (begin (printf "You tried to divide by zero.  Try again.~n")
                                          (div n))))])
        (check-div4 n d div-zero-exn-handler)))))

#|
;; something went wrong, let the programmer correct the problem
(define (div-adjust n)
  (printf "Enter a denominator: ")
  (let ([result (with-handlers ([(lambda (exn) (symbol=? exn 'div-zero-exn))
                                 (lambda (exn) 0)])
                  (check-div4 n (read)))])
    (+ result 7)))
|# 

(define (div-adjust n)
  (printf "Enter a denominator: ")
  (let ([result 
         (let/cc div-zero-exn-point
           (let ([div-zero-exn-handler
                  (lambda () (div-zero-exn-point 0))])
             (check-div4 n (read) div-zero-exn-handler)))])
    (+ result 7)))
