1

我是 Haskell 的新手,所以这可能是一个愚蠢的问题。我正在读一本书,上面写着:type sum应该显示sum :: (Num a) => [a] -> a。而不是该消息是sum :: (Num a, Foldable t) => t a -> a. 正如我在https://www.haskell.org/hoogle/?hoogle=Sum中看到的那样,这种差异是由于 - 我认为 - 存在两个不同的 sum 函数。也许这类似于 Java 中的多态性,我才刚刚开始,我不知道 Haskell 是如何工作的。

所以我的问题是:我如何使用 sum 函数来sum :: (Num a) => [a] -> a代替另一种类型?你能解释一下这里发生了什么吗?

4

1 回答 1

2

正如我在https://www.haskell.org/hoogle/?hoogle=Sum中看到的那样,这种差异是由于 - 我认为 - 存在两个不同的 sum 函数。也许这类似于 Java 中的多态性

确实,它是多态性,尽管不是以这种方式(请参阅此答案末尾的 PS)。注意...

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,它必须具有类的实例,Foldable实例涵盖的功能,如sum,可能表示为将容器扁平化为列表,然后以某种方式折叠它。

PS:您的书说的与您所看到的有所不同,因为直到最近,sumPrelude 中的函数还具有不太通用的列表特定类型,并且您的书早于更改。调用两个不同的函数sum,即使一个比另一个更通用,也会导致名称冲突(出于类似的原因,我导入了Data.Set上面示例中限定的模块 - 这样做是个好主意因为它定义了一些函数,例如map与 Prelude 函数发生冲突的函数,并且用它们来限定它们S.map可以避免任何问题)。

于 2016-11-15T18:33:15.460 回答