Reputation: 8641
I'm a complete newbie to Haskell. I type this into WinGHCi and it works fine:
> let x = 0.5
> let n = 5
> map (\y->(x**y)) [0..n]
[1.0,0.5,0.25,0.125,6.25e-2,3.125e-2] -- notice it is powers of 1/2 !
But when I define a simple function in a file:
powersOfx :: (Integral a, Floating b) => a -> b -> [b]
powersOfx n x = map (\y->(x**y)) [0..n]
and type
:l myFile
, I get:
Couldn't match expected type ‘b’ with actual type ‘a’
‘a’ is a rigid type variable bound by
the type signature for:
powersOfx :: forall a b. (Integral a, Floating b) => a -> b -> [b]
What's going on? Am I doing the signature incorrectly? I'm guessing I might be, because when I just comment it out and :l myFile it works but
:t powersOfx
I get:
powersOfx :: (Floating b, Enum b) => b -> b -> [b]
Notice the 'Enum' instead of 'Integral'.
I suppose I could just get rid of the type signature but I'm under the impression it's good practice to put a signature AND I'm trying to solve a larger problem where I'm getting error reported here: Ambiguous type variable `a0' arising from a use of `it'
If I get this part working, I'll post a separate question about that!
Please let me know if I'd be better off posting to another group or if I should be posting more information.
-Dave
Upvotes: 1
Views: 100
Reputation: 477617
map (\y->(x**y)) [0..n]
functionIn short: your signature is too broad, one can design Floating
types such that the function can not be called.
Let us first analyze the types you use here:
Prelude> let x = 0.5
Prelude> let n = 5
Prelude> :t map (\y->(x**y)) [0..n]
map (\y->(x**y)) [0..n] :: (Enum b, Floating b) => [b]
Prelude> :t \n x -> map (\y->(x**y)) [0..n]
\n x -> map (\y->(x**y)) [0..n]
:: (Enum b, Floating b) => b -> b -> [b]
So what we see here is that the output type b
, actually has to be an instance of two typeclasses: Enum
, and Floating
. That is logical: you use [0..n]
, so that means that you ask Haskell to enumerate all elements between 0
and n
, but a number is not per se enumerable (in fact we can already wonder that Floating
is Enum
erable in the first place: here we make hops of one, but we thus omit the Floating
values in between, in case we would have a real float, then enumerating is even impossible).
As a result the y
s have the same type as n
, and since we perform arithmetic with x
and y
(we write x ** y
), this thus means that x
and y
need to have the same type since (**)
has type (**) :: Floating a => a -> a -> a
. We can thus construct a function:
powersOfx :: (Enum b, Floating b) => b -> b -> [b]
powersOfx n x = map (\y->(x**y)) [0..n]
But this is a bad idea. Floating
is usually something we better avoid as much as possible: if the number is large, we can have all sorts of rounding errors. We could use fromIntegral :: (Integral a, Num b) => a -> b
, but again this can result in rounding errors when we convert for example a large Int
to a Float
. In that case the type would be:
powersOfx :: (Enum b, Floating b, Integral a) => a -> b -> [b]
powersOfx n x = map (\y->(x**y)) [0..fromIntegral n]
Nevertheless we can make the function more flexible and generic, by using iterate :: (a -> a) -> a -> [a]
and by using the take :: Int -> [a] -> [a]
(or genericTake :: Integral i => i -> [a] -> [a]
):
import Data.List(genericTake)
powersOfx :: (Integral i, Num n) => i -> n -> [n]
powersOfx n x = genericTake (n+1) (iterate (x*) 1)
This then produces:
Prelude Data.List> f 5 0.5
[1.0,0.5,0.25,0.125,6.25e-2,3.125e-2]
Upvotes: 3