我是Haskell的新手,所以这可能是一个愚蠢的问题。我正在读一本书,其中:type sum
应该显示sum :: (Num a) => [a] -> a
。而不是消息是sum :: (Num a, Foldable t) => t a -> a
。正如我在https://www.haskell.org/hoogle/?hoogle=Sum中看到的那样,这种差异是由于 - 我认为 - 存在两个不同的和函数。也许它就像Java中的多态,我刚刚开始,我不知道Haskell是如何工作的。
所以我的问题是:我如何使用类型为sum :: (Num a) => [a] -> a
的sum函数而不是另一个?你能解释一下这里发生了什么吗?
答案 0 :(得分:2)
正如我在https://www.haskell.org/hoogle/?hoogle=Sum中所见,这种差异是由于 - 我认为 - 存在两种不同的和函数。也许它就像Java中的多态性
确实是多态性,但不是这样(参见本答案末尾的P.S.)。请注意......
sum :: (Num a) => [a] -> a
...已经在被求和的数字类型中具有多态性,因此它可以用于Integer
列表和Double
列表。这与......之间的区别。
sum :: (Num a, Foldable t) => t a -> a
...这个sum
在容器的类型中也是多态的:
GHCi> -- +t makes GHCi print the types automatically.
GHCi> :set +t
GHCi> sum [1 :: Integer, 2, 3]
6
it :: Integer
GHCi> sum [1 :: Double, 2, 3]
6.0
it :: Double
GHCi> import qualified Data.Set as S
GHCi> :t S.fromList
S.fromList :: Ord a => [a] -> S.Set a
GHCi> sum (S.fromList [1 :: Double, 2, 3])
6.0
it :: Double
对于要与sum
一起使用的容器类型,它必须具有the Foldable
class的实例,其中包含的函数(如sum
)可能表示为将容器展平为列表然后以某种方式折叠它。
P.S。:你的书说的不同于你所看到的东西,因为直到最近,Prelude中的sum
函数过去常常使用不那么通用的特定于列表的类型,而你的书早于改变。有两个不同的函数sum
,即使一个严格比另一个更通用,也会导致名称冲突(这是因为我导入了上面示例中限定的Data.Set
模块的类似原因 - 这样做是个好主意,因为它定义了一些与Prelude函数冲突的map
函数,并使用S.map
来限定它们,避免任何问题)。