了解Haskell中的类型

时间:2014-03-16 18:09:31

标签: haskell types

我正在尝试将函数h映射到素数列表。两者都在下面给出:

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 ]

但是当我尝试map h primes时,我收到以下错误:

Ambiguous type variable `a0' in the constraints:
  (Enum a0)
    arising from the arithmetic sequence `3, 5 .. '

依旧......

函数f和素数似乎都按预期工作但我不能将f应用于素数中的数字???我在这里误解了什么?

3 个答案:

答案 0 :(得分:2)

您的函数primes的类型为[Integer]

您的函数h的类型为Double -> Integer

map的类型是这样的:

ghci> :t map
map :: (a -> b) -> [a] -> [b]

或者当专门用于Integer列表时,它的类型签名变为:

map :: (Integer -> b) -> [Integer] -> [b]

但是,您传递给h的{​​{1}}函数的类型为map,因此它没有进行类型检查,因为它期望Double -> Integer而不是Integer -> b功能接受Double

始终尝试在功能之前编写类型签名,这将使您的生活更轻松。

答案 1 :(得分:1)

问题

primes :: Integral a => [a]h :: (RealFrac a, Integral b, Floating a) => a -> b。现在,没有任何类型都是RealFracIntegral的实例,但GHC并不知道这一点,因此它给出的错误消息有点令人困惑。

原因

log :: Floating a => a -> a(/) :: Fractional a => a -> a -> afloor :: (RealFrac a, Integral b) => a -> b,因此当我们撰写它们时,我们会获得上述类型的签名。 Haskell具有强大的数字类型,这意味着整数和浮点类型之间没有隐式转换。

解决方案

使用显式转换函数fromIntegral :: (Integral a, Num b) => a -> b

map (h . fromIntegral) primes

答案 2 :(得分:0)

primes有哪些类型?这完全取决于具体情况。它可能是

primes :: [Integer]

或其他。目前尚不清楚,因为像3这样的文字具有类型3 :: Num a => a。我们唯一可以肯定的是,无论需要什么样的Enum实例,否则[3,5..]都无法正常工作。

现在f的类型是什么? f在其参数上使用log,然后将结果置于底层,因此我们可以期待类似

的内容
f :: (RealFrac a, Floating a, Integral b) => a -> a -> b

但是,这已经暗示您无法将其与map一起使用,因为map期望(a -> b)作为第一个参数。更重要的是,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

因此我们需要更改primes类型或f的类型。我们更改f的类型:

f k x = floor ( log (fromIntegral k) / log (fromIntegral x) )

现在我们可以按预期使用f p1 p2

*Main> let (p1:p2:_) = primes
*Main> f p1 p2
0

map问题呢? map期望(a -> b)作为第一个参数,f仍为(a -> b -> c) *。从您当前的代码中,您似乎想要使用两个连续的素数并应用f。为此,我们首先使用uncurry

uncurry :: (a -> b -> c) -> (a, b) -> c

现在uncurry f(a, b) -> c。但现在列表(primes)不是对列表。但是,我们可以很容易地解决这个问题,我们zip用它的尾部填充:

map (uncurry f) (zip primes $ tail primes)

这就是如何在单个列表的连续元素上映射具有两个参数的函数。


* k或x可以是不同的积分类型