Multiple folds in one pass using generic tuple function

前端 未结 2 918
渐次进展
渐次进展 2021-02-08 07:22

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

2条回答
  •  爱一瞬间的悲伤
    2021-02-08 07:48

    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'.

提交回复
热议问题