求和函数中的不同类型

Different types in sum function

我是 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 的求和函数而不是另一种?你能给我解释一下这是怎么回事吗?

As I've seen in https://www.haskell.org/hoogle/?hoogle=Sum this difference is due to -I think- the existence of two different sum functions. Maybe it's something like polymorphism in 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 来限定它们可以避免任何问题)。