module Strategies where import Control.Parallel (par,pseq) import Ix import Array infixl 0 `using`,`demanding`,`sparking` -- weakest precedence! type Done = () type Strategy a = a -> Done using :: a -> Strategy a -> a using x s = s x `pseq` x demanding, sparking :: a -> Done -> a demanding = flip pseq sparking = flip par r0 :: Strategy a r0 x = () rwhnf :: Strategy a rwhnf x = x `pseq` () class NFData a where -- rnf reduces its argument to (head) normal form rnf :: Strategy a -- Default method. Useful for base types. A specific method is necessay for -- constructed types rnf = rwhnf class (NFData a, Integral a) => NFDataIntegral a class (NFData a, Ord a) => NFDataOrd a instance (NFData a, NFData b) => NFData (a,b) where rnf (x,y) = rnf x `pseq` rnf y instance (NFData a, NFData b, NFData c) => NFData (a,b,c) where rnf (x,y,z) = rnf x `pseq` rnf y `pseq` rnf z instance (NFData a, NFData b, NFData c, NFData d) => NFData (a,b,c,d) where rnf (x1,x2,x3,x4) = rnf x1 `pseq` rnf x2 `pseq` rnf x3 `pseq` rnf x4 -- code automatically inserted by `hwl-insert-NFData-n-tuple' instance (NFData a1, NFData a2, NFData a3, NFData a4, NFData a5) => NFData (a1, a2, a3, a4, a5) where rnf (x1, x2, x3, x4, x5) = rnf x1 `pseq` rnf x2 `pseq` rnf x3 `pseq` rnf x4 `pseq` rnf x5 -- code automatically inserted by `hwl-insert-NFData-n-tuple' instance (NFData a1, NFData a2, NFData a3, NFData a4, NFData a5, NFData a6) => NFData (a1, a2, a3, a4, a5, a6) where rnf (x1, x2, x3, x4, x5, x6) = rnf x1 `pseq` rnf x2 `pseq` rnf x3 `pseq` rnf x4 `pseq` rnf x5 `pseq` rnf x6 -- code automatically inserted by `hwl-insert-NFData-n-tuple' instance (NFData a1, NFData a2, NFData a3, NFData a4, NFData a5, NFData a6, NFData a7) => NFData (a1, a2, a3, a4, a5, a6, a7) where rnf (x1, x2, x3, x4, x5, x6, x7) = rnf x1 `pseq` rnf x2 `pseq` rnf x3 `pseq` rnf x4 `pseq` rnf x5 `pseq` rnf x6 `pseq` rnf x7 -- code automatically inserted by `hwl-insert-NFData-n-tuple' instance (NFData a1, NFData a2, NFData a3, NFData a4, NFData a5, NFData a6, NFData a7, NFData a8) => NFData (a1, a2, a3, a4, a5, a6, a7, a8) where rnf (x1, x2, x3, x4, x5, x6, x7, x8) = rnf x1 `pseq` rnf x2 `pseq` rnf x3 `pseq` rnf x4 `pseq` rnf x5 `pseq` rnf x6 `pseq` rnf x7 `pseq` rnf x8 -- code automatically inserted by `hwl-insert-NFData-n-tuple' instance (NFData a1, NFData a2, NFData a3, NFData a4, NFData a5, NFData a6, NFData a7, NFData a8, NFData a9) => NFData (a1, a2, a3, a4, a5, a6, a7, a8, a9) where rnf (x1, x2, x3, x4, x5, x6, x7, x8, x9) = rnf x1 `pseq` rnf x2 `pseq` rnf x3 `pseq` rnf x4 `pseq` rnf x5 `pseq` rnf x6 `pseq` rnf x7 `pseq` rnf x8 `pseq` rnf x9 seqPair :: Strategy a -> Strategy b -> Strategy (a,b) seqPair strata stratb (x,y) = strata x `pseq` stratb y parPair :: Strategy a -> Strategy b -> Strategy (a,b) parPair strata stratb (x,y) = strata x `par` stratb y `par` () seqTriple :: Strategy a -> Strategy b -> Strategy c -> Strategy (a,b,c) seqTriple strata stratb stratc p@(x,y,z) = strata x `pseq` stratb y `pseq` stratc z parTriple :: Strategy a -> Strategy b -> Strategy c -> Strategy (a,b,c) parTriple strata stratb stratc (x,y,z) = strata x `par` stratb y `par` stratc z `par` () instance NFData Int instance NFData Integer instance NFData Float instance NFData Double instance NFDataIntegral Int instance NFDataOrd Int instance NFData Char instance NFData Bool instance NFData () instance NFData a => NFData [a] where rnf [] = () rnf (x:xs) = rnf x `pseq` rnf xs parList :: Strategy a -> Strategy [a] parList strat [] = () parList strat (x:xs) = strat x `par` (parList strat xs) parListN :: (Integral b) => b -> Strategy a -> Strategy [a] parListN n strat [] = () parListN 0 strat xs = () parListN n strat (x:xs) = strat x `par` (parListN (n-1) strat xs) parListNth :: Int -> Strategy a -> Strategy [a] parListNth n strat xs | null rest = () | otherwise = strat (head rest) `par` () where rest = drop n xs parMap :: Strategy b -> (a -> b) -> [a] -> [b] parMap strat f xs = map f xs `using` parList strat parFlatMap :: Strategy [b] -> (a -> [b]) -> [a] -> [b] parFlatMap strat f xs = concat (parMap strat f xs) parZipWith :: Strategy c -> (a -> b -> c) -> [a] -> [b] -> [c] parZipWith strat z as bs = zipWith z as bs `using` parList strat seqList :: Strategy a -> Strategy [a] seqList strat [] = () seqList strat (x:xs) = strat x `pseq` (seqList strat xs) seqListN :: (Integral a) => a -> Strategy b -> Strategy [b] seqListN n strat [] = () seqListN 0 strat xs = () seqListN n strat (x:xs) = strat x `pseq` (seqListN (n-1) strat xs) seqListNth :: Int -> Strategy b -> Strategy [b] seqListNth n strat xs | null rest = () | otherwise = strat (head rest) where rest = drop n xs parBuffer :: Int -> Strategy a -> [a] -> [a] parBuffer n s xs = return xs (start n xs) where return (x:xs) (y:ys) = (x:return xs ys) `sparking` s y return xs [] = xs start n [] = [] start 0 ys = ys start n (y:ys) = start (n-1) ys `sparking` s y instance (Ix a, NFData a, NFData b) => NFData (Array a b) where rnf x = rnf (bounds x) `pseq` seqList rnf (elems x) `pseq` () seqArr :: (Ix b) => Strategy a -> Strategy (Array b a) seqArr s arr = seqList s (elems arr) parArr :: (Ix b) => Strategy a -> Strategy (Array b a) parArr s arr = parList s (elems arr) fstPairFstList :: (NFData a) => Strategy [(a,b)] fstPairFstList = seqListN 1 (seqPair rwhnf r0) force :: (NFData a) => a -> a sforce :: (NFData a) => a -> b -> b force x = rnf x `pseq` x sforce x y = force x `pseq` y