(define (sum f start stop inc)
  (cond
    [(> start stop) 0]
    [else (+ (f start) (sum f (+ start inc) stop inc))]))

(define (integrate f a b n)
  (let ((h (/ (- b a) n)))
    (let ((start (+ a (/ h 2)))
          (stop (- b (/ h 2))))
      (* h (sum f start stop h)))))

;; these represent a different kind of recursion!

(define tolerance 0.00001)

(define (close-enough? v1 v2)
            (< (abs (- v1 v2)) tolerance))

(define (fixed-point f x0)
  (local ((define (try x)
            (local ((define next (f x)))
              (cond
                [(close-enough? x next) next]
                [else (try next)]))))
    (try x0)))

(define (midpoint a b) (/ (+ a b) 2))

(define (bisect-search f neg pos)
  (let ((mp (midpoint neg pos)))
    (if (close-enough? neg pos)
        mp
        (let ((fm (f mp)))
          (cond 
            [(positive? fm) (bisect-search f neg mp)]
            [(negative? fm) (bisect-search f mp pos)]
            [else mp])))))
    
(define (half-interval-method f a b)
  (let ((fa (f a))
        (fb (f b)))
    (cond
      [(and (negative? fa) (positive? fb)) (bisect-search f a b)]
      [(and (positive? fa) (negative? fb)) (bisect-search f b a)]
      [else (error "Values not of opposite sign" a b)])))

(define dx .0001)
(define (deriv g)
  (lambda (x) (/ (- (g (+ x dx)) (g x)) dx)))

(define (newton-mapping f)
  (lambda (x) (- x (/ (f x) ((deriv f) x)))))

(define (newtons-method f x0)
  (fixed-point (newton-mapping f) x0))

;; what about integrating repeatedly until we converge
(define (integrate-till-convergence f a b n)
  (local ((define (iter prevint curint curn)
            (if (close-enough? prevint curint) 
                curint
                (let ((nextn (* curn 2)))
                  (iter curint (integrate f a b nextn) nextn)))))
    (iter (integrate f a b n) (integrate f a b (* n 2)) (* n 2))))