2011-07-19 149 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