考虑来自Prelude的功能,如zipWith
。还有其他函数,如zipWith3
... zipWith7
,它们的区别仅在于参数的数量。有许多类似的例子,在其他语言中也是如此(scala,ocaml)。
创建具有特定数量元素的函数的原因是什么?为什么不使用通用版?也许从应用参数的数量中得出特定的zipWith
答案 0 :(得分:11)
zipWith
的广义版本确实存在:它是ZipList
applicative functor:
import Control.Applicative
zipWith f a1 a2 = getZipList (f <$> ZipList a1 <*> ZipList a2)
zipWith3 f a1 a2 a3 = getZipList (f <$> ZipList a1 <*> ZipList a2 <*> ZipList a3)
等等。问题是,通常使用zipWithN
函数来更快地使用ZipList
构造函数包装所有内容。
编辑: chi的评论指出,我并不像我应该那样清楚。关键是ZipList
包装器允许我们使用适用的f <$> x1 <*> ... <*> xn
成语来压缩任何数量的元素类型与f
类型兼容的列表。
答案 1 :(得分:7)
理论上可以在Haskell中编写一个具有可变数量参数的函数,有些库很好地使用它,但没有什么能够超越编译器可以更容易地优化的单个函数的清晰度和效率。 zipWithN
功能易于使用,对初学者和高级用户都有意义,并且能够很好地完成工作。
如果您需要所有列表具有相同类型的N路zipWith
,请使用Data.List.transpose
:
zipWithN :: ([a] -> b) -> [[a]] -> [b]
zipWithN f = map f . transpose
如果您需要列表具有不同类型,那么您可能会错误地解决它。根据定义,异类列表在Haskell和大多数其他静态类型语言中并不是微不足道的。
答案 2 :(得分:5)
通用函数的主要目的是可以使用它们来编写其他多态代码,而不会有麻烦。这可能会非常reduce code duplication。
然而,对于像通用zipWith
这样的东西几乎不可能:至少在你使用它的地方,你需要有一些固定的数量的列表参数,否则编译器无法确定组合器函数是否也具有正确数量的参数。因此,这种通用函数的唯一优点是您只需要一个公开的名称。这是不太有益的,当你遇到错误时,它几乎不会超过更加模糊的错误消息的缺点,并且当事情变得太多多态时偶尔需要显式的本地签名。