I've defined the following function:
calculateApproximation :: Int -> Int -> Int -> Double -> Double
calculateApproximation n a r tol =
if abs(((take n xs)!!(n-1)) - (((take n xs)!!(n-2)))) <= tol
then ((take n xs)!!(n-1))
else calculateApproximation (n+1) a r tol
where xs = unfoldr (\x -> Just(x, (x + (r/x))/2)) a
But I'm seeing the following type error:
Couldn't match expected type `Int' with actual type `Double'
In the second argument of `(<=)', namely `tol'
In the expression:
abs (((take n xs) !! (n - 1)) - (((take n xs) !! (n - 2)))) <= tol
But then, why is it expecting tol to be an Int, when I've already defined it as Double? Or is there a totally silly mistake I'm overlooking here?
The simplest fix is to modify the type signature so that your initial guess a and the number you are computing the square root of, r, are Double rather than Int.
I've also taken the liberty of factoring out the definition ys = take n xs to simplify the code a little.
calculateApproximation :: Int -> Double -> Double -> Double -> Double
calculateApproximation n a r tol =
if abs (ys!!(n-1) - ys!!(n-2)) <= tol
then ys!!(n-1)
else calculateApproximation (n+1) a r tol
where xs = unfoldr (\x -> Just(x, (x + (r/x))/2)) a
ys = take n xs
However, as was pointed out in the comments, you don't actually need to take n elements before looking up the n-1th element. You can apply !! to infinite lists, which simplifies your code further to
calculateApproximation :: Int -> Double -> Double -> Double -> Double
calculateApproximation n a r tol =
if abs (xs!!(n-1) - xs!!(n-2)) <= tol
then xs!!(n-1)
else calculateApproximation (n+1) a r tol
where xs = unfoldr (\x -> Just(x, (x + (r/x))/2)) a
I would probably factor out a few more definitions for clarity, giving
calculateApproximation' n a r tol = go n
where
go n = let eps = abs $ xs!!(n-1) - xs!!(n-2)
in if eps <= tol
then xs !! (n-1)
else go (n+1)
xs = unfoldr (\x -> Just (x, (x + r/x)/2)) a
Finally, I would notice that the operation go only ever uses the n-1 and n-2 elements of the list, never the earlier elements, and that the index n is only used to keep track of where you are in the list. So I would rewrite so that go operates on the list, rather than on the index, and have it iterate through the list until it finds a suitable answer. And in one minor tidy-up, I'd change from unfoldr to iterate -- you only really want unfoldr if the list is supposed to terminate at some point.
calculateApproximation a r tol = go xs
where
go (x:y:rest) = if abs (x-y) < tol
then y
else go (y:rest)
xs = iterate (\x -> (x+r/x)/2) a
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With