[英]Understanding types in Haskell
I am trying to map a function, h, to a list of primes. 我正在尝试将函数h映射到素数列表。 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: 但是,当我尝试
map h primes
,出现以下错误:
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??? 函数f和素数似乎都能按预期工作,但我无法将f应用于素数中的数字??? What am I misunderstanding here?
我在这里误会什么?
Your function primes
is of type [Integer]
. 您的函数
primes
是类型[Integer]
。
Your function h
is of type Double -> Integer
. 您的函数
h
是Double -> Integer
类型的。
The type of map
is like this: map
的类型如下:
ghci> :t map
map :: (a -> b) -> [a] -> [b]
Or when specialized to a list of Integer
it's type signatures becomes: 或者,当专门处理
Integer
列表时,其类型签名将变为:
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
. 但是要传递给
map
h
函数的类型为Double- Double -> Integer
,因此不会进行类型检查,因为它期望的是Integer- Integer -> b
而不是接受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
. primes :: Integral a => [a]
和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. 现在,没有任何类型同时是
RealFrac
和Integral
实例,但是GHC不知道这一点,因此它给出的错误消息有点令人困惑。
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. log :: Floating a => a -> a
floor :: (RealFrac a, Integral b) => a -> b
log :: Floating a => a -> a
, (/) :: Fractional a => a -> a -> a
floor :: (RealFrac a, Integral b) => a -> b
(/) :: Fractional a => a -> a -> a
floor :: (RealFrac a, Integral b) => a -> b
(/) :: Fractional a => a -> a -> a
和floor :: (RealFrac a, Integral b) => a -> b
,所以当我们撰写他们我们得到上面的类型签名。 Haskell has strong number types and this means that there are no implicit conversions between integer and floating point types. Haskell具有强大的数字类型,这意味着整数和浮点类型之间没有隐式转换。
Use the explicit conversion function fromIntegral :: (Integral a, Num b) => a -> b
: 使用显式转换函数
fromIntegral :: (Integral a, Num b) => a -> b
:
map (h . fromIntegral) primes
What type does primes
have? primes
有什么类型? 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
. 目前尚不清楚,因为像
3
这样的文字的类型为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. 我们唯一可以确定的是,无论它是
Enum
的实例是什么,否则[3,5..]
将无法工作。
Now what's the type of f
? 现在
f
是什么类型? f
uses log
on it's arguments, and then floors the result, so we can expect something like f
使用log
作为参数,然后对结果取底,因此我们可以期待类似
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. 但是,这已经暗示您不能将其与
map
一起使用,因为map
需要将(a -> b)
a- (a -> b)
作为第一个参数。 And more important, the elements of primes
don't fulfill the Floating
constraint: 更重要的是,
primes
元素不满足Floating
约束:
*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. 因此,我们需要更改
primes
类型或f
的类型。 We change f
's type: 我们更改
f
的类型:
f k x = floor ( log (fromIntegral k) / log (fromIntegral x) )
Now we can use f p1 p2
as expected: 现在我们可以按预期使用
f p1 p2
:
*Main> let (p1:p2:_) = primes
*Main> f p1 p2
0
But what about the map
issue? 但是
map
问题呢? map
expects (a -> b)
as first parameter, and f
is still (a -> b -> c)
*. map
期望(a -> b)
a- (a -> b)
作为第一个参数,而f
仍然是(a -> b -> c)
*。 From your current code it seems like you would like to use two consecutive primes and apply f
. 从您当前的代码看来,您似乎想使用两个连续的素数并应用
f
。 For this, we first use uncurry
: 为此,我们首先使用
uncurry
:
uncurry :: (a -> b -> c) -> (a, b) -> c
Now uncurry f
has (a, b) -> c
. 现在,
uncurry f
具有(a, b) -> c
。 But now the list ( primes
) isn't a list of pairs. 但是现在列表(质
primes
)不再是配对列表。 However, we can fix this easily, we zip
primes with its tail: 但是,我们可以很容易地解决此问题,我们用尾部
zip
素数:
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 * k或x可以是不同的积分类型
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.