I am trying to map a function, h, to a list of primes. Both are given below:
f k x = floor ( log k / log x )
h = f 20
primes = 2 : sieve [3,5..]
where
sieve (p:xs) = p:[ x | x <- xs, x `mod` p > 0 ]
However when I try map h primes
I get the following error:
Ambiguous type variable `a0' in the constraints:
(Enum a0)
arising from the arithmetic sequence `3, 5 .. '
and so on...
Both the function f and primes seem to work as expected but I cannot apply f to the numbers in primes??? What am I misunderstanding here?
Your function primes
is of type [Integer]
.
Your function h
is of type Double -> Integer
.
The type of map
is like this:
ghci> :t map
map :: (a -> b) -> [a] -> [b]
Or when specialized to a list of Integer
it's type signatures becomes:
map :: (Integer -> b) -> [Integer] -> [b]
But your h
function which you are passing to map
is of type Double -> Integer
and hence it doesn't typecheck because it is expecting something of Integer -> b
and not a function accepting Double
.
Always try to write type signature before function, that will make your life easier.
primes :: Integral a => [a]
and h :: (RealFrac a, Integral b, Floating a) => a -> b
. Now, there aren't any types that are instances of both RealFrac
and Integral
but GHC doesn't know this, so the error message it gives is a bit confusing.
log :: Floating a => a -> a
, (/) :: Fractional a => a -> a -> a
and floor :: (RealFrac a, Integral b) => a -> b
, so when we compose them we get the above type signature. Haskell has strong number types and this means that there are no implicit conversions between integer and floating point types.
Use the explicit conversion function fromIntegral :: (Integral a, Num b) => a -> b
:
map (h . fromIntegral) primes
What type does primes
have? That completely depends on the circumstances. It could be
primes :: [Integer]
or something else. It isn't clear, since literals like 3
have the type 3 :: Num a => a
. The only thing we can be sure about, is that whatever it is need to be an instance of Enum
, otherwise [3,5..]
couldn't work.
Now what's the type of f
? f
uses log
on it's arguments, and then floors the result, so we can expect something like
f :: (RealFrac a, Floating a, Integral b) => a -> a -> b
However, this already hints that you cannot use it with map
, since map
expects (a -> b)
as first parameter. And more important, the elements of primes
don't fulfill the Floating
constraint:
*Main> let (p1:p2:_) = primes
*Main> f p1 p2
<interactive>:29:1:
No instance for (RealFrac Integer) arising from a use of `f'
Possible fix: add an instance declaration for (RealFrac Integer)
In the expression: f p1 p2
In an equation for `it': it = f p1 p2
So we either need to change primes
type or f
's type. We change f
's type:
f k x = floor ( log (fromIntegral k) / log (fromIntegral x) )
Now we can use f p1 p2
as expected:
*Main> let (p1:p2:_) = primes
*Main> f p1 p2
0
But what about the map
issue? map
expects (a -> b)
as first parameter, and f
is still (a -> b -> c)
*. From your current code it seems like you would like to use two consecutive primes and apply f
. For this, we first use uncurry
:
uncurry :: (a -> b -> c) -> (a, b) -> c
Now uncurry f
has (a, b) -> c
. But now the list ( primes
) isn't a list of pairs. However, we can fix this easily, we zip
primes with its tail:
map (uncurry f) (zip primes $ tail primes)
And that's how you can map a function with two parameters on consecutive elements of a single list.
*k or x could be of different Integral types
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.