2011-07-19 43 views
4

说,我们可以写这样的事:使用运营商zipWithN

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

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

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

现在,我想要做同样的事情,但使用添加,而不是逗号运算符。 有没有办法在同一个简洁的方式来定义它不使用Lambda表达式像

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

先谢谢您的任何答复。

+0

这不是问题的主要观点,你可能知道这一点,但'zipWith(,)'是'zip','zipWith3(,,)'是'zip3',等等。 –

回答

12

这听起来像你想要“免费”的样式代码为\a b c -> a + b + c。要知道,一般来说,\a b c -> a + b + c通常更适合指向免费代码,因为在发现错误时四周后再阅读更容易。

有关于免费编程的wiki文章()。

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

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

所以((+) .) . (+)是点免费版本(X,Y和Z是“点”,如果你想知道,也没有,这有什么用几何形状做)。如果你愿意的话,你可以使用这个定义,但大多数人会看你的代码,不知道这个有趣的ASCII艺术应该做什么。他们中的一半会用铅笔和纸做出来,但不是原来的\x y z -> x + y + z那么容易在眼睛上?

提示:如果你需要弄清楚一些点免费代码做什么,看看类型:

 
Prelude> :t ((+) .) . (+) 
((+) .) . (+) :: (Num a) => a -> a -> a -> a 

或者你可以安装pointful包,这是大约的pointfree倒数。

摘要:欢迎来到积分免费编程的世界,请谨慎行事,以免您的代码难以辨认。

+0

迪特里希,谢谢你的回答。对我来说,这种编程风格总是让人难以理解,因为实际上我们经常在无点代码中使用很多点)是的,我知道((+)。)。(+),但我不能称它更简洁版本) – shabunc

+0

为什么是((+)。)。 (+)'不是更简洁的版本? –

+0

@Dietrich如果你想要做的事更常见,那么做一个更简单的方法。 – augustss

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] 
+0

nope。这样我们正在改变输入数据的结构。如果我们有[[a]]而不是我们可以轻松完成sum $ concat [[1,2,3],[4,5,6],[7,8,9]] – shabunc

+0

@shabunc:warning:' sum $ concat [[1,2,3],[4,5,6],[7,8,9]]'不同于'foldr1(zipWith(+))[[1,2,3] ,[4,5,6],[7,8,9]]' – MarcoS

+0

是的,这是所有事情总和之前的一步。 – shabunc

7

另一种选择:应用性函子。实际上,控制。应用性包含NEWTYPE定义ZipList(因为有应用性的用于列表类型几个可能的定义),其可以这样使用:

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等)。

+0

有时我希望ZipList是列表的默认应用实例,因为它非常方便。当然有一个很好的理由,但它仍然很好。 –

4

绕过zipWith3,你可以这样做:

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

在使用zipWith3切割输出到最短的名单,这不,即对[[1,2],[3]它给[4 ,2]。

+0

正如我已经对MarcoS所说的那样,通过改变输入的数据结构,我们可以使用很多不同的方法 - 例如sum $ map sum [[1,2,3],[4,5,6],[7, 8,9]] – shabunc

+0

@shabunc:此代码计算与zipWith3(\ abc - > a + b + c)...完全相同的内容,仅当列表长度不同时才有所不同。 sum $ map sum [[1,2,3],[4,5,6],[7,8,9]]计算sum(1 + 2 + 3)+(4 + 5 + 6)+(7+ 8 + 9)而sum $ map sum $ transpose [[1,2,3],[4,5,6],[7,8,9]]计算sum(1 + 4 + 7)+(2 + 5 8)+(3 + 6 + 9)。确切地说是 – sdcvvc

+0

,但是在这两种情况下输入数据的结构都不同于这个问题。如果我们有任何类似[[a]]的东西,我们可以使用列表操作函数的所有范围。 – shabunc