2013-05-21 86 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