Skip to content

Commit 6c49946

Browse files
committed
Better rolling buffer strategies (haskell#77)
1 parent 735dda4 commit 6c49946

File tree

1 file changed

+25
-60
lines changed

1 file changed

+25
-60
lines changed

Control/Parallel/Strategies.hs

Lines changed: 25 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -652,68 +652,33 @@ parFmap strat f = (`using` parTraversable strat) . fmap f
652652
-- --------------------------------------------------------------------------
653653
-- Strategies for lazy lists
654654

655-
-- List-based non-compositional rolling buffer strategy, evaluating list
656-
-- elements to weak head normal form.
657-
-- Not to be exported; used in evalBuffer and for optimisation.
658-
evalBufferWHNF :: Int -> Strategy [a]
659-
evalBufferWHNF n0 xs0 = return (ret xs0 (start n0 xs0))
660-
where -- ret :: [a] -> [a] -> [a]
661-
ret (x:xs) (y:ys) = y `pseq` (x : ret xs ys)
662-
ret xs _ = xs
663-
664-
-- start :: Int -> [a] -> [a]
665-
start 0 ys = ys
666-
start !_n [] = []
667-
start !n (y:ys) = y `pseq` start (n-1) ys
668-
669-
-- | 'evalBuffer' is a rolling buffer strategy combinator for (lazy) lists.
670-
-- Evaluation of the ith element induces evaluation of the (i+n)th element,
671-
-- with the first n elements being evaluated immediately.
672-
--
673-
-- 'evalBuffer' is not as compositional as the type suggests. In fact,
674-
-- it evaluates list elements at least to weak head normal form,
675-
-- disregarding a strategy argument 'r0'.
676-
--
677-
-- > evalBuffer n r0 == evalBuffer n rseq
678-
--
655+
-- | 'evalBuffer' is a rolling buffer strategy combinator for lazy lists.
656+
-- Pattern matching on the result of @evalBuffer n strat xs@ will evaluate the
657+
-- first @n+1@ elements of @xs@ using @strat@. Pattern matching on each
658+
-- additional list cons will evaluate an additional element using @strat@.
679659
evalBuffer :: Int -> Strategy a -> Strategy [a]
680-
evalBuffer n strat = evalBufferWHNF n . map (withStrategy strat)
681-
682-
-- Like evalBufferWHNF, but sparks the list elements when pushing them
683-
-- into the buffer.
684-
-- Not to be exported; used in parBuffer and for optimisation.
685-
parBufferWHNF :: Int -> Strategy [a]
686-
parBufferWHNF n0 xs0 = return (ret xs0 (start n0 xs0))
687-
where -- ret :: [a] -> [a] -> [a]
688-
ret (x:xs) (y:ys) = y `par` (x : ret xs ys)
689-
ret xs _ = xs
690-
691-
-- start :: Int -> [a] -> [a]
692-
start 0 ys = ys
693-
start !_n [] = []
694-
start !n (y:ys) = y `par` start (n-1) ys
695-
696-
697-
-- | Like 'evalBuffer', but evaluates the list elements in parallel when
698-
-- pushing them into the buffer.
699-
-- Evaluation of the ith element induces parallel evaluation of the (i+n)th element,
700-
-- with the first n elements being evaluated in parallel immediately.
701-
--
702-
-- > parBuffer n strat = evalBuffer n (rparWith strat)
660+
evalBuffer n0 strat xs0 = return (ret tied (drop n0 tied))
661+
where
662+
-- This is the heart of the strategy. The idea is to tie the evaluation
663+
-- of each cons (to WHNF) to the evaluation of its contents (according
664+
-- to strat). Walking the spine of the result will thus perform
665+
-- the requested Eval actions.
666+
tied = foldr go [] xs0
667+
where
668+
go x r = runEval ((: r) <$> strat x)
669+
670+
ret (x : xs) (_y : ys) = x : ret xs ys
671+
ret xs _ = xs
672+
673+
-- | 'parBuffer' is a rolling buffer strategy combinator for lazy lists.
674+
-- Pattern matching on the result of @parBuffer n s xs@ sparks
675+
-- computations to evaluate the first @n+1@ elements of @xs@ using the
676+
-- strategy @s@. Pattern matching on each additional list cons will
677+
-- spark an additional computation.
678+
--
679+
-- @parBuffer n strat = 'evalBuffer' n ('rparWith' strat)@
703680
parBuffer :: Int -> Strategy a -> Strategy [a]
704-
parBuffer n strat = parBufferWHNF n . map (withStrategy strat)
705-
-- Alternative definition via evalBuffer (may compromise firing of RULES):
706-
-- parBuffer n strat = evalBuffer n (rparWith strat)
707-
708-
-- Deforest the intermediate list in parBuffer/evalBuffer when it is
709-
-- unnecessary:
710-
711-
{-# NOINLINE [1] evalBuffer #-}
712-
{-# NOINLINE [1] parBuffer #-}
713-
{-# RULES
714-
"evalBuffer/rseq" forall n . evalBuffer n rseq = evalBufferWHNF n
715-
"parBuffer/rseq" forall n . parBuffer n rseq = parBufferWHNF n
716-
#-}
681+
parBuffer n strat = evalBuffer n (rparWith strat)
717682

718683
-- --------------------------------------------------------------------------
719684
-- Strategies for tuples

0 commit comments

Comments
 (0)