2013-05-21 125 views
15

有時您想使用不同的摺疊函數將元組列表摺疊到一個元組中。例如,爲了將runState結果列表粘貼在一起,獲得(某種意義上)組合狀態和組合結果。使用箭頭摺疊元組列表

考慮以下實現:

wish :: (a -> a' -> a) -> (b -> b' -> b) -> (a,b) -> [(a', b')] -> (a,b) 
wish lfn rfn x xs = foldl (\(a,b) -> (lfn a) *** (rfn b)) x xs 

雖然它的作品,我覺得不舒服關於這個拉姆達。 lfn *** rfn本身有一種(a,b) -> (a -> a', b -> b')類型,我無法找到一種正確應用於元組而無需訴諸模式匹配的方法。有沒有一種清晰而優雅的方式我錯過了?它可能是(a,a') -> (a -> a, a' -> a') -> (a, a')類型的庫函數,或者可能是一個完全不同的方法。

+2

某種類型的BiApplicative類可以做。有可能是某個地方有瑕疵,但我會將其留給其他人以涵蓋哪些是好的並且不被棄用。 – Carl

+0

http://squing.blogspot.com/2008/11/beautiful-folding.html及其在Hackage上的實例化,http://hackage.haskell.org/package/ZipFold –

回答

9

Control.Arrow不重視更高級的功能。你真正需要的是一個函數foo :: (a -> a' -> a'') -> (b -> b' -> b'') -> (a,b) -> (a',b') -> (a'',b'')(***)的模擬函數爲函數2.在Data.Biapplicative中有一個函數(來自包bifunctor),它具有更一般的簽名biliftA2 :: Biapplicative w => (a -> b -> c) -> (d -> e -> f) -> w a d -> w b e -> w c f。由於雙元組元組有一個Biapplicative實例,這就是你所需要的。

我可以看到你的代碼的唯一抱怨是,它的lambda的currying是不明顯的;我可能更喜歡更明確的\(a,b) (a',b') -> (lfn a a', rfn b b')

編輯筆記:我已經斷定所需函數不存在,並建議定義它;在Carl的評論的鼓勵下,我發現了一個在Biapplicative(更一般的類型簽名阻止Hoogle根據我的建議簽名找到它的人)。

+0

用'\(a ,b)(a',b') - > ...有點違背使用一些花哨的概念寫全能的單行程的全部目的。感謝您提及Biapplicative,我會研究它。 –

+0

我的觀點是儘管Biapplicative的'(<<**>>)'確實有你需要應用的類型(lfn *** rfn),但是在這裏箭頭的調用似乎不適合我。但那只是我的直覺。如果不一定清楚,基於箭頭的方法是正確的。但我更喜歡'(lfn \'biLiftA2 \'rfn)'顯式lambda。 – isturdy