How can I write a function which takes a tuple of functions of type ai -> b -> ai
and returns a function which takes a tuple of elements of type ai
For a direct approach, you can just define the equivalents of Control.Arrow
's (***)
and (&&&)
explicitly, for each N
(e.g. N == 4
):
prod4 (f1,f2,f3,f4) (x1,x2,x3,x4) = (f1 x1,f2 x2,f3 x3,f4 x4) -- cf (***)
call4 (f1,f2,f3,f4) x = (f1 x, f2 x, f3 x, f4 x ) -- cf (&&&)
uncurry4 f (x1,x2,x3,x4) = f x1 x2 x3 x4
Then,
foldr4 :: (b -> a1 -> a1, b -> a2 -> a2,
b -> a3 -> a3, b -> a4 -> a4)
-> (a1, a2, a3, a4) -> [b]
-> (a1, a2, a3, a4) -- (f .: g) x y = f (g x y)
foldr4 t z xs = foldr (prod4 . call4 t) z xs -- foldr . (prod4 .: call4)
-- f x1 (f x2 (... (f xn z) ...)) -- foldr . (($) .: ($))
So the tuple's functions in foldr4
's are flipped versions of what you wanted. Testing:
Prelude> g xs = foldr4 (min, max, (+), (*)) (head xs, head xs, 0, 1) xs
Prelude> g [1..5]
(1,5,15,120)
foldl4'
is a tweak away. Since
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
we have
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)
We've even got the types as you wanted, for the tuple's functions.
A stricter version of prod4
had to be used to force the arguments early in foldl4'
.