Parallel "Fold" in Haskell
I have a function with a type below:
union :: a -> a -> a
And ahas the property of additivity . Therefore, we can consider it unionas a version(+)
Let's say we have [a]and want to execute a parallel "folding", for non-parallel bending we can only do:
foldl1' union [a]
But how to do this in parallel? I can demonstrate the problem by Numand (+).
For example, we have a list [1,2,3,4,5,6]and in (+)
parallel we have to split
[1,2,3] (+) [4,5,6]
[1,2] (+) [3] (+) [4,5] (+) [6]
([1] (+) [2]) (+) ([3] (+) [4]) (+) ([5] (+) [6])
then each operation (+)that we want to perform in parallel, and combine to respond
[3] (+) [7] (+) [11] = 21
Please note that we break the list or perform operations in any order due to aadditivity.
?
union & oplus; , (a & oplus; b) & oplus; c == a & oplus; (b & oplus; c). , & oplus;, .
, & oplus; , a & oplus; (b & oplus; (c & oplus; d)) == (a & oplus; b) & oplus; (c & oplus; d) - ; "" "" , .
, , chunking , & oplus; - do & oplus; , chunking. - "" - , . Data.Array.Repa .
, , & oplus; .
:
import Control.Parallel
import Data.List
pfold :: (Num a, Enum a) => (a -> a -> a) -> [a] -> a
pfold _ [x] = x
pfold mappend xs = (ys `par` zs) `pseq` (ys `mappend` zs) where
len = length xs
(ys', zs') = splitAt (len `div` 2) xs
ys = pfold mappend ys'
zs = pfold mappend zs'
main = print $ pfold (+) [ foldl' (*) 1 [1..x] | x <- [1..5000] ]
-- need a more complicated computation than (+) of numbers
-- so we produce a list of products of many numbers
, mappend , , , parallelism; parallelism , mempty.
ghc -O2 -threaded a.hs
a +RTS -N1 -s
8,78 ,
a +RTS -N2 -s
5,89 . , -N2.
, , . GHCI:
Prelude> :m + Data.Monoid
Prelude Data.Monoid> :info Monoid
class Monoid a where
mempty :: a
mappend :: a -> a -> a
mconcat :: [a] -> a
, :
mempty. ,Num: sum product.mempty0.mempty1.mempty `mappend` a = a a `mappend` mempty = amappendunion.Nummappend(+),Nummappend(*).mconcat. - , , . ,mappend:(a `mappend` b) `mappend` c = a `mappend` (b `mappend` c)
, , Haskell . , Monoid typeclass, , .
, union : a -> a -> a. , . . . union ?
, :
newtype Sum a = Sum { getSum :: a }
instance Num a => Monoid (Sum a) where
mempty = 0
mappend = (+)
. mconcat, , mempty mappend. , mempty mappend, mconcat .
Sum :
getSum . mconcat $ map Sum [1..6]
, :
Sum[1..6][Sum 1, Sum 2, Sum 3, Sum 4, Sum 5, Sum 6].mconcat,Sum 21.getSumNumSum 21.
, , mconcat - foldr mappend mempty (.. ). . :
foldParallel :: Monoid a => [a] -> a
foldParallel [] = mempty
foldParallel [a] = a
foldParallel xs = foldParallel left `mappend` foldParallel right
where size = length xs
index = (size + size `mod` 2) `div` 2
(left, right) = splitAt index xs
Monoid :
data Something a = Something { getSomething :: a }
instance Monoid (Something a) where
mempty = unionEmpty
mappend = union
mconcat = foldParallel
:
getSomething . mconcat $ map Something [1..6]
, mempty unionEmpty. , union. , mempty . , unionEmpty. .