Prelude为什么只有不同的args具有相同的功能?

sig*_*ami 4 haskell

考虑来自Prelude的功能zipWith.还有其他函数,例如zipWith3...... zipWith7,它们只有参数的数量不同.有许多类似的例子,在其他语言中也是如此(scala,ocaml).

创建具有特定数量元素的函数的原因是什么?为什么不使用通用版?也许zipWith从应用的参数数量中得出特别的结果

Lui*_*las 11

zipWith确实存在广义版本:它是ZipList应用程序的函子:

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)
Run Code Online (Sandbox Code Playgroud)

等等.问题是,使用构造zipWithN函数包装所有内容的函数通常会更快ZipList.


编辑: chi的评论指出我并不像我应该那样清楚.关键是ZipList包装器允许我们使用适用的f <$> x1 <*> ... <*> xn习语来压缩任何数量的元素类型与类型兼容的列表f.


bhe*_*ilr 7

理论上可以在Haskell中编写一个具有可变数量参数的函数,一些库很好地使用它,但是没有什么能够超越编译器可以更容易地优化单个函数的清晰度和效率.这些zipWithN功能易于使用,对初学者和高级用户都有意义,并且能够很好地完成工作.

如果你需要一个zipWith所有列表都具有相同类型的N路,那么只需使用Data.List.transpose:

zipWithN :: ([a] -> b) -> [[a]] -> [b]
zipWithN f = map f . transpose
Run Code Online (Sandbox Code Playgroud)

如果你需要列表有不同的类型,你可能会错了.根据定义,异构列表在Haskell和大多数其他静态类型语言中并不是微不足道的.

  • 可以使用[`ZipList`](https://hackage.haskell.org/package/base-4.8.0.0/docs/Control-Applicative.html#t:ZipList)应用程序轻松完成不同类型案例的列表. (3认同)

lef*_*out 5

广义函数的主要目的是您可以使用它们来编写其他多态代码,而不会有麻烦.这可以大大减少代码重复.

然而,这几乎不可能像通用的东西zipWith:至少在你使用它的地方,你需要有一些固定数量的列表参数,否则编译器不能确定组合器函数也有正确数量的参数.因此,这种通用函数的唯一优点是您只需要一个公开的名称.这是不太有益的,当你遇到错误时,它几乎不会超过更加模糊的错误消息的缺点,并且当事情变得过于多态时偶尔需要显式的局部签名.