Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell - expected type vs. actual type

Tags:

types

haskell

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?

like image 434
jl.lykon Avatar asked Nov 23 '25 11:11

jl.lykon


1 Answers

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
like image 76
Chris Taylor Avatar answered Nov 25 '25 10:11

Chris Taylor