4

我刚开始用 Haskell 编程,我正在解决99 个 Haskell 问题,当我几乎完成第 10 个问题时,我遇到了这个问题:

-- Exercise 9
pack :: Eq a => [a] -> [[a]]
pack [] = []
pack list = let (left,right) = span (== head list) list in
            left : pack right

-- Exercise 10        
encode :: (Eq a, Integral c) => [a] -> [(c, a)]
encode [] = []
encode list = map (\x -> (length x, head x)) (pack list)
-- this doesn't work      ^^^^^^^^

产生的错误告诉我

Could not deduce (c ~ Int)
from the context (Eq a, Integral c)
  bound by the type signature for
             encode :: (Eq a, Integral c) => [a] -> [(c, a)]
  at C:\fakepath\ex.hs:6:11-47
  `c' is a rigid type variable bound by
      the type signature for
        encode :: (Eq a, Integral c) => [a] -> [(c, a)]
      at C:\fakepath\ex.hs:6:11
In the return type of a call of `length'
In the expression: length x
In the expression: (length x, head x) 

我已经设法通过插入一个我在Learn you a Haskell中读到的函数来解决这个问题:fromIntegral

encode list = map (\x -> (fromIntegral $ length x, head x)) (pack list)

所以,我的问题是,为什么需要这样做

我已经运行:t length并得到了[a] -> Int,这对我来说是一个非常定义的类型,它应该满足Integral c约束。

4

1 回答 1

9

类型签名(Eq a, Integral c) => [a] -> [(c, a)]意味着该函数适用于任何类型ac适当的类型类。实际使用的类型在调用站点指定。

作为一个简单的例子,我们来看看空列表的类型:

:t []
[a]

这意味着它[]代表一个空列表StringInt一个空列表,一个空列表Maybe [Maybe Bool]以及你能想象到的任何其他类型。我们可以想象将其包装在一个普通的标识符中:

empty :: [a]
empty = []

empty显然与[]. 所以你可以看到下面的定义没有意义:

empty :: [a]
empty = [True]

毕竟,[True]永远不能是一个[Int][String]任何其他你想要的空列表。

这里的想法是相同的,除了我们对变量也有类型类约束。例如,您可以使用encode返回一个[(Integer, String)]列表,因为Integer它也在Integral类中。

所以你必须返回一些可以是任何 Integral多态的东西——只是什么fromIntegral。如果您刚刚返回Intencode则只能用作 anInt而不是 any Integral

于 2013-08-05T15:20:08.480 回答