Zoey Hewll
Zoey Hewll

Reputation: 5385

Can't make function more polymorphic

I'm trying to define a function to return each of the nth roots of unity.
This compiles,

unity n = map (cis.(*2).(*pi).(/n)) [0..(n-1)]

but its type defaults to unity :: (Enum a, Floating a) => a -> [Complex a].
Of course, n needs to be an integer, as roots of unity aren't defined otherwise; but the returned Complex numbers will necessarily have floating-point coordinates; i.e, they cannot be Complex Ints. However, the following code won't compile

unity :: (Integral a, Floating b) => a -> [Complex b]
unity n = map (cis . (* 2) . (* pi) . (/ n)) [0..(n - 1)]

because (/) (*) and cis each constrain the return type (or Complex coordinate type in the case of cis) to be the same as the parameter type; so I get the error

Couldn't match expected type ‘b’ with actual type ‘a’

Is there a way I can force the parameter to be an integer without forcing the complex numbers to have integral components?

Upvotes: 2

Views: 79

Answers (1)

Zoey Hewll
Zoey Hewll

Reputation: 5385

All you need to do is coerce your Integral parameter to a Num with fromIntegral when your code expects a value of the same type as the return type, i.e. as arguments to cis, (*) or (/). Though n is only directly passed into (/), so that's all you need to worry about:

unity :: (Integral a, Floating b) => a -> [Complex b]
unity n = map (cis . (* 2) . (* pi) . (/ (fromIntegral n)) . fromIntegral) [0..(n-1)]

Upvotes: 4

Related Questions