如果采用直接的方法,您可以为每个 N(例如 N == 4)明确定义 Control.Arrow 的 ( ***) 和 (&&&) 等效项:
prod4 (f1,f2,f3,f4) (x1,x2,x3,x4) = (f1 x1,f2 x2,f3 x3,f4 x4)
call4 (f1,f2,f3,f4) x = (f1 x, f2 x, f3 x, f4 x )
uncurry4 f (x1,x2,x3,x4) = f x1 x2 x3 x4
那么,
foldr4 :: (b -> a1 -> a1, b -> a2 -> a2,
b -> a3 -> a3, b -> a4 -> a4)
-> (a1, a2, a3, a4) -> [b]
-> (a1, a2, a3, a4)
foldr4 t z xs = foldr (prod4 . call4 t) z xs
因此,元组在foldr4
中的函数是你所需的翻转版本。测试:
Prelude> g xs = foldr4 (min, max, (+), (*)) (head xs, head xs, 0, 1) xs
Prelude> g [1..5]
(1,5,15,120)
foldl4'
只需要进行一些调整即可。因为
foldr f z xs == foldl (\k x r-> k (f x r)) id xs z
foldl f z xs == foldr (\x k a-> k (f a x)) id xs z
我们有
foldl4, foldl4' :: (t -> a -> t, t1 -> a -> t1,
t2 -> a -> t2, t3 -> a -> t3)
-> (t, t1, t2, t3) -> [a]
-> (t, t1, t2, t3)
foldl4 t z xs = foldr (\x k a-> k (call4 (prod4 t a) x))
(prod4 (id,id,id,id)) xs z
foldl4' t z xs = foldr (\x k a-> k (call4 (prod4' t a) x))
(prod4 (id,id,id,id)) xs z
prod4' (f1,f2,f3,f4) (x1,x2,x3,x4) = (f1 $! x1,f2 $! x2,f3 $! x3,f4 $! x4)
我们已经按照你的要求为元组函数提供了所需的类型。
foldl4'
需要使用prod4
的严格版本来提前强制参数。