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

虽然它有效,但我对这个 lambda 感到不舒服。lfn *** rfn本身有一种类型(a,b) -> (a -> a', b -> b'),我无法找到一种方法来正确应用到元组而不求助于模式匹配。我想念一种清晰而优雅的方式吗?它可能是类型的库函数(a,a') -> (a -> a, a' -> a') -> (a, a')或完全不同的方法。

4

1 回答 1

9

Control.Arrow不太关注高阶函数。你真正想要的是一个函数foo :: (a -> a' -> a'') -> (b -> b' -> b'') -> (a,b) -> (a',b') -> (a'',b''),类似于(***)arity 2 的函数。 Data.Biapplicative 中有这样一个函数(来自包 bifunctor),它具有更通用的签名biliftA2 :: Biapplicative w => (a -> b -> c) -> (d -> e -> f) -> w a d -> w b e -> w c f。由于二元素元组有一个 Biapplicative 实例,这就是你所需要的。

我能看到的对您的代码的唯一抱怨是 lambda 的柯里化并不明显;我可能更喜欢更明确的\(a,b) (a',b') -> (lfn a a', rfn b b').

编辑说明:我得出的结论是所需的功能不存在,并建议定义它;在 Carl 的评论的推动下,我在 Biapplicative 中找到了那个(更通用的类型签名阻止了 Hoogle 在我建议的签名下找到它)。

于 2013-05-21T18:52:15.803 回答