If you look at your code for this exercise as well as the one about approximating the square root and the one about finding epsi, you'll notice a common pattern:
You have a function which performs a single step and a predicate which tells you when you're done. You then apply the stepping function until the predicate is met. When you encounter a common pattern like this, the best thing to do is usually to abstract it. So let's define an apply-until
function which takes a stepping function, a predicate and an initial value and applies the function to the value until the predicate is met:
(define (apply-until step done? x)
(if (done? x) x
(apply-until (step x) step done?)))
You can now define your cuberoot
function using apply-until
instead of cuberoot-iter
:
(define (cuberoot x)
(apply-until (lambda (y) (improve-guess y x)) (lambda (guess) (goodenough? guess)) 1.0))
You can also move your helper functions as local functions into the cuberoot
function. This way they don't need to take x
as an argument (as they will close over it) and can thus be passed directly to apply-until
without using lambda
:
(define (cuberoot x)
(define (improveguess y)
; y is a guess for cuberoot(x)
(/ (+ (/ x (expt y 2)) (* 2 y)) 3))
(define (goodenough? guess)
(< (/ (abs (- (cube guess) x)) guess) 0.0001))
(apply-until improveguess goodenough? 1.0))