4

说,我们可以这样写:

zipWith (,) [1,2,3] [4,5,6]

如果我们想要 tuple 3 列表,我们可以这样写: zipWith3 (,,) [1,2,3] [4,5,6] [7,8,9]

我们也可以使用 zipWith4 (,,,) zipWith5(,,,,)等等。

现在,我想做同样的事情,但使用添加而不是逗号运算符。有没有办法以同样简洁的方式定义它,而不是像 in 那样使用 lambdas

zipWith3 (\a b c -> a + b + c) [1, 2, 3] [4, 5, 6] [7, 8, 9]

提前感谢您的任何回答。

4

4 回答 4

12

听起来您想要\a b c -> a + b + c. 让我们知道,通常,\a b c -> a + b + c通常比指向免费代码更可取,因为当您发现错误时,它更容易在四个星期后阅读。

有一篇关于无点编程的 wiki 文章(来源)。

您还可以安装该pointfree软件包,它可以让您在命令行上解决这些问题。例如,

$ pointfree '\xyz -> x + y + z'
((+)。)。(+)

无点版本也是如此((+) .) . (+)(x、y 和 z 是“点”,以防您想知道,不,这与几何无关)。如果您愿意,您可以使用该定义,但大多数人会查看您的代码,并且不知道那个看起来很有趣的 ASCII 艺术应该做什么。他们中的一半会用铅笔和纸来解决它,但原版不是\x y z -> x + y + z更容易对眼睛吗?

提示:如果您需要弄清楚某些免费代码的作用,请查看类型:

前奏> :t ((+) .) . (+)
((+)。)。(+) :: (Num a) => a -> a -> a -> a

或者你可以安装这个pointful包,它大约是pointfree.

摘要:欢迎来到无积分编程的世界,请谨慎操作,以免您的代码无法阅读。

于 2011-07-19T09:27:38.223 回答
7

另一种选择:应用函子。事实上,Control.Applicative 包含新类型定义ZipList(因为对于列表类型有几种可能的 Applicative 定义),可以这样使用:

import Control.Applicative 

getZipList $ (,,) <$> ZipList [1,2,3] <*> ZipList [4,5,6] <*> ZipList [7,8,9]

或类似的(对于几个(+)的):

getZipList $ (+) <$> ((+) <$> ZipList [1,2,3] <*> ZipList [4,5,6]) <*> ZipList [7,8,9]

尽管对这个特定问题使用应用函子可能没有多大意义,但它们仍然为解决类似类型的任务提供了非常强大的抽象/机制,因此它们绝对值得学习(例如,我们可以摆脱 zipWith3、zipWith4 ... ETC)。

于 2011-07-19T10:31:21.177 回答
4

Bypassing zipWith3, you can do:

import Data.List (transpose)
map sum $ transpose [[1,2,3],[4,5,6],[7,8,9]]

While using zipWith3 cuts the output to shortest list, this doesn't, i.e. for [[1,2],[3]] it gives [4,2].

于 2011-07-19T12:27:37.710 回答
2

我认为没有 lamda 就无法编写它。实际上zipWith3需要一个函数作为第一个参数,该函数接受 3 个参数,并且(+)只接受两个参数。因此,您需要定义“带有 3 个参数的加号函数”,这正是您的 lambda 所做的。

另一种选择是:

foldr1 (zipWith (+)) [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ]

不知道上面是不是更简洁

zipWith3 (\a b c -> a + b + c) [1, 2, 3] [4, 5, 6] [7, 8, 9]
于 2011-07-19T10:20:46.220 回答