I tried:
import Data.VectorSpace -- ^/
import Data.AdditiveGroup -- sumV
import Data.Foldable -- length
avg :: (Foldable f, VectorSpace a) => f a -> a
avg xs = sm ^/ sz -- could be just ^*(1/sz)
where sm = sumV xs
sz = fromIntegral (length xs)
and got:
Distancesumcurves.hs:11:10: error:
• Could not deduce (Fractional (Scalar a))
arising from a use of ‘^/’
from the context: (Foldable f, VectorSpace a)
bound by the type signature for:
avg :: (Foldable f, VectorSpace a) => f a -> a
at Distancesumcurves.hs:10:1-46
• In the expression: sm ^/ sz
In an equation for ‘avg’:
avg xs
= sm ^/ sz
where
sm = sumV xs
sz = fromIntegral (length xs)
Distancesumcurves.hs:13:13: error:
• Could not deduce (Num (Scalar a))
arising from a use of ‘fromIntegral’
from the context: (Foldable f, VectorSpace a)
bound by the type signature for:
avg :: (Foldable f, VectorSpace a) => f a -> a
at Distancesumcurves.hs:10:1-46
• In the expression: fromIntegral (length xs)
In an equation for ‘sz’: sz = fromIntegral (length xs)
In an equation for ‘avg’:
avg xs
= sm ^/ sz
where
sm = sumV xs
sz = fromIntegral (length xs)
Of course I could just write one specifically for vectors, and get on with my life, but then whats the point of the generic features of Haskell. In a less pedantic language I would be done with it already, and it would work just fine, and it would be reusable. In Haskell I have to write a question here or regress to code-duplication. I consider this a failure of the language.
Its not the first time I got frustrated with Haskell generics. I am past the level of the book Programming in Haskell by Graham Hutton. What should be the next step/book/article for me? So that I dont get into arguments with the compiler, when I know what I want, and it is correct. Its just language-technical skill I lack in this case. Feel free to correct me if I am wrong.
edit:
seems to work in context
approximateCurve :: [Point] -> Path
approximateCurve pts = [] -- TODO
where center = avg pts
avg vs = (sum vs) ^/ (fromIntegral (length vs))
sum = foldr (^+^) (0,0)
In this case, I would add the additional constraint suggested in the error message, to get avg :: (Foldable f, VectorSpace a, Fractional (Scalar a)) => f a -> a
.
Fractional
implies Num
, so no need to mention Num
. Also no harm if you add it - the function is not made less generic.
As far as general advice, I think writing lots of generic functions, guided by the type errors, is the best way. Often adding the suggested constraints is enough; other times you really want the more-general signature, and need to figure out which function is bringing in the unwanted constraint.