Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell implementation of the law of cosines

I am trying to implement the law of cosines function, and here is my code:

cosC :: [a] -> a
cosC sides
   | length sides < 3          = 0
   | otherwise                 = (x ^ 2 + y ^ 2 - z ^ 2) / (2 * x * y)
   where x = head(tail(tail(sides)))
         y = head(tail(sides))
         z = head(sides)

But I get two errors:

No instance for (Fractional a)
arising from a use of `/'
In the expression: (x ^ 2 + y ^ 2 - z ^ 2) / (2 * x * y)
In an equation for `cosC':
    cosC sides
      | length sides < 3 = 0
      | otherwise = (x ^ 2 + y ^ 2 - z ^ 2) / (2 * x * y)
      where
          x = head (tail (tail (sides)))
          y = head (tail (sides))
          z = head (sides)

and

No instance for (Num a)
arising from the literal `2'
In the first argument of `(*)', namely `2'
In the first argument of `(*)', namely `2 * x'
In the second argument of `(/)', namely `(2 * x * y)'

Edit: I have fixed the sign typo in the law of cosines above. Thanks to Daniel Fischer for pointing that out.

like image 976
User3419 Avatar asked Dec 05 '22 13:12

User3419


1 Answers

You're trying to calculate numerical results out of general types a, that can't possibly work. (It's like trying to build a bridge not just for general road-vehicles but for general things, e.g. spaceships, skyscrapers, paper clips and neutron stars). Just add the Floating constraint to a:

cosC :: Floating a => [a] -> a

and you can perform any of the arithmetic operations you need for such a calculation. (Fractional is actually enough for this function, but you won't be able to calculate the arccos of the result then).


Unrelated to your problem, note that there's a much better way to decompose lists in Haskell:

cosC (x:y:z:_) = (x^2 + y^2 - z^2) / (2*x*y)
cosC _ = 0

is equivalent to your definition. Why are you taking the arguments as a list anyway? That's quite a Lisp-ish thing to do, in Haskell I'd prefer

cosC :: Floating a => a -> a -> a -> a
cosC x y z = (x^2 + y^2 - z^2) / (2*x*y)
like image 162
leftaroundabout Avatar answered Jan 06 '23 20:01

leftaroundabout