diff --git a/Control/Parallel.hs b/Control/Parallel.hs
--- a/Control/Parallel.hs
+++ b/Control/Parallel.hs
@@ -1,71 +1,46 @@
+{-# LANGUAGE CPP #-}
+
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Control.Parallel
 -- Copyright   :  (c) The University of Glasgow 2001
 -- License     :  BSD-style (see the file libraries/base/LICENSE)
--- 
+--
 -- Maintainer  :  libraries@haskell.org
--- Stability   :  experimental
--- Portability :  non-portable
+-- Stability   :  stable
+-- Portability :  portable
 --
--- Parallel Constructs
+-- Parallel constructs.
 --
+-- A common pattern to evaluate two values in parallel is:
+--
+-- > x `par` y `pseq` someFunc x y
+--
+-- The effect of this pattern is to cause @x@ to be evaluated in
+-- parallel with @y@. When the evaluation of @y@ is complete, computation
+-- proceeds by evaluating @someFunc x y@.
+--
 -----------------------------------------------------------------------------
 
 module Control.Parallel (
-          par, pseq,
-	  seq, -- for backwards compatibility, 6.6 exported this
-#if defined(__GRANSIM__)
-	, parGlobal, parLocal, parAt, parAtAbs, parAtRel, parAtForNow     
-#endif
+          par, pseq
     ) where
 
-import Prelude
-
 #ifdef __GLASGOW_HASKELL__
-import qualified GHC.Conc	( par, pseq )
-
-infixr 0 `par`, `pseq`
+import qualified GHC.Conc (par, pseq)
 #endif
 
-#if defined(__GRANSIM__)
-import PrelBase
-import PrelErr   ( parError )
-import PrelGHC   ( parGlobal#, parLocal#, parAt#, parAtAbs#, parAtRel#, parAtForNow# )
-
-infixr 0 `par`
-
-{-# INLINE parGlobal #-}
-{-# INLINE parLocal #-}
-{-# INLINE parAt #-}
-{-# INLINE parAtAbs #-}
-{-# INLINE parAtRel #-}
-{-# INLINE parAtForNow #-}
-parGlobal   :: Int -> Int -> Int -> Int -> a -> b -> b
-parLocal    :: Int -> Int -> Int -> Int -> a -> b -> b
-parAt	    :: Int -> Int -> Int -> Int -> a -> b -> c -> c
-parAtAbs    :: Int -> Int -> Int -> Int -> Int -> a -> b -> b
-parAtRel    :: Int -> Int -> Int -> Int -> Int -> a -> b -> b
-parAtForNow :: Int -> Int -> Int -> Int -> a -> b -> c -> c
-
-parGlobal (I# w) (I# g) (I# s) (I# p) x y = case (parGlobal# x w g s p y) of { 0# -> parError; _ -> y }
-parLocal  (I# w) (I# g) (I# s) (I# p) x y = case (parLocal#  x w g s p y) of { 0# -> parError; _ -> y }
-
-parAt       (I# w) (I# g) (I# s) (I# p) v x y = case (parAt#       x v w g s p y) of { 0# -> parError; _ -> y }
-parAtAbs    (I# w) (I# g) (I# s) (I# p) (I# q) x y = case (parAtAbs#  x q w g s p y) of { 0# -> parError; _ -> y }
-parAtRel    (I# w) (I# g) (I# s) (I# p) (I# q) x y = case (parAtRel#  x q w g s p y) of { 0# -> parError; _ -> y }
-parAtForNow (I# w) (I# g) (I# s) (I# p) v x y = case (parAtForNow# x v w g s p y) of { 0# -> parError; _ -> y }
-
-#endif
+infixr 0 `par`, `pseq`
 
 -- Maybe parIO and the like could be added here later.
 
 -- | Indicates that it may be beneficial to evaluate the first
 -- argument in parallel with the second.  Returns the value of the
 -- second argument.
--- 
--- @a `par` b@ is exactly equivalent semantically to @b@.
 --
+-- The result of @a ``par`` b@ is always  @b@, regardless of whether
+-- @a@ evaluates to a bottom, so for example @par undefined x = x@.
+--
 -- @par@ is generally used when the value of @a@ is likely to be
 -- required later, but not immediately.  Also it is a good idea to
 -- ensure that @a@ is not a trivial computation, otherwise the cost of
@@ -73,20 +48,24 @@
 -- running it in parallel.
 --
 -- Note that actual parallelism is only supported by certain
--- implementations (GHC with the @-threaded@ option, and GPH, for
--- now).  On other implementations, @par a b = b@.
---
+-- implementations (GHC with the @-threaded@ option, for now).
+-- On other implementations, @par a b = b@.
 par :: a -> b -> b
 #ifdef __GLASGOW_HASKELL__
 par = GHC.Conc.par
 #else
--- For now, Hugs does not support par properly.
+-- For now, Hugs and MicroHs don't support par properly.
 par a b = b
 #endif
 
--- | Semantically identical to 'seq', but with a subtle operational
--- difference: 'seq' is strict in both its arguments, so the compiler
--- may, for example, rearrange @a `seq` b@ into @b `seq` a `seq` b@.
+-- | Like 'seq' but ensures that the first argument is evaluated before returning.
+--
+-- @a ``pseq`` b@ evaluates @a@ to weak head normal form (WHNF)
+-- before returning @b@.
+--
+-- This is similar to 'seq', but with a subtle difference:
+-- 'seq' is strict in both its arguments, so the compiler
+-- may, for example, rearrange @a ``seq`` b@ into @b ``seq`` a ``seq`` b@.
 -- This is normally no problem when using 'seq' to express strictness,
 -- but it can be a problem when annotating code for parallelism,
 -- because we need more control over the order of evaluation; we may
@@ -97,7 +76,6 @@
 -- strict in its first argument (as far as the compiler is concerned),
 -- which restricts the transformations that the compiler can do, and
 -- ensures that the user can retain control of the evaluation order.
---
 pseq :: a -> b -> b
 #ifdef __GLASGOW_HASKELL__
 pseq = GHC.Conc.pseq
diff --git a/Control/Parallel/Strategies.hs b/Control/Parallel/Strategies.hs
--- a/Control/Parallel/Strategies.hs
+++ b/Control/Parallel/Strategies.hs
@@ -1,605 +1,989 @@
------------------------------------------------------------------------------
--- |
--- Module      :  Control.Parallel.Strategies
--- Copyright   :  (c) The University of Glasgow 2001
--- License     :  BSD-style (see the file libraries/base/LICENSE)
--- 
--- Maintainer  :  libraries@haskell.org
--- Stability   :  experimental
--- Portability :  non-portable
---
--- Parallel strategy combinators. See
--- <http://www.macs.hw.ac.uk/~dsg/gph/papers/html/Strategies/strategies.html>
--- for more information.
---
--- Original authors:
---	Phil Trinder, Hans-Wolfgang Loidl, Kevin Hammond et al. 
---
------------------------------------------------------------------------------
-module Control.Parallel.Strategies (
-   -- *	Strategy Type, Application and Semantics
-   Done, Strategy,
-   (>|), (>||),
-   using, demanding, sparking,
-   -- *	Basic Strategies				     
-   r0, rwhnf, NFData(..),
-   -- * Strategic Function Application
-   ($|), ($||),
-   (.|), (.||),
-   (-|), (-||),
-   -- * Tuples
-   seqPair, parPair,
-   seqTriple, parTriple,
-   -- * Lists: Parallel Strategies
-   parList, parListN, parListNth, parListChunk, 
-   parMap, parFlatMap, parZipWith,
-   -- * Lists: Sequential Strategies
-   seqList, seqListN, seqListNth, parBuffer,
-   -- *	Arrays
-   seqArr, parArr,
-   -- * Deprecated types and functions
-   sPar, sSeq,
-   Assoc(..),
-   fstPairFstList, force, sforce
-  ) where
-
--- based on hslibs/concurrent/Strategies.lhs; see it for more detailed
--- code comments. 
-
-import Control.Parallel as Parallel (par, pseq)
-import Data.Array
-import Data.Complex
-import Data.Int
-import qualified Data.IntMap (IntMap, toList)
-import qualified Data.IntSet (IntSet, toList)
-import qualified Data.Map (Map, toList)
-import qualified Data.Set (Set, toList)
-import qualified Data.Tree (Tree(..))
-import Data.Word
-
-import Prelude hiding (seq)
-import qualified Prelude (seq)
-
--- not a terribly portable way of getting at Ratio rep.
-#ifdef __GLASGOW_HASKELL__
-import GHC.Real	(Ratio(..))	-- The basic defns for Ratio
-#endif
-
-#ifdef __HUGS__
-import Hugs.Prelude(Ratio(..) )
-#endif
-
-#ifdef __NHC__
-import Ratio (Ratio(..) )
-#endif
-
-infixl 0 `using`,`demanding`,`sparking`              -- weakest precedence!
-
-infixr 2 >||                -- another name for par
-infixr 3 >|                 -- another name for seq
-infixl 6 $||, $|            -- strategic function application (seq and par)
-infixl 9 .|, .||, -|, -||   -- strategic (inverse) function composition
-
-infixl 0 `seq`
-
--- We need 'pseq', not the Prelude 'seq' here.  See the documentation
--- with 'pseq' in Control.Parallel.
-seq = Parallel.pseq
-
-------------------------------------------------------------------------------
--- *			Strategy Type, Application and Semantics	      
-------------------------------------------------------------------------------
-
-{-
-The basic combinators for strategies are 'par' and 'seq' but with types that 
-indicate that they only combine the results of a strategy application. 
-
-NB: This version can be used with Haskell 1.4 (GHC 2.05 and beyond), *but*
-    you won't get strategy checking on seq (only on par)!
-
-The operators >| and >|| are alternative names for `seq` and `par`.
-With the introduction of a Prelude function `seq` separating the Prelude 
-function from the Strategy function becomes a pain. The notation also matches
-the notation for strategic function application.
--}
-
-type Done = ()
-
--- | A strategy takes a value and returns a 'Done' value to indicate that
---   the specifed evaluation has been performed.
-type Strategy a = a -> Done
-
-
--- | Evaluates the first argument before the second.
-(>|) :: Done -> Done -> Done 
-{-# INLINE (>|) #-}
-(>|) = Prelude.seq
-
--- | Evaluates the first argument in parallel with the second.
-(>||) :: Done -> Done -> Done 
-{-# INLINE (>||) #-}
-(>||) = Parallel.par
-
-
--- | Takes a value and a strategy, and applies the strategy to the
--- value before returning the value. Used to express data-oriented 
--- parallelism. @x \`using\` s@ is a projection on @x@, i.e. both:
---
--- [a retraction] @x \`using\` s@ &#x2291; @x@
---
--- [idempotent] @(x \`using\` s) \`using\` s@ = @x \`using\` s@
---
-using :: a -> Strategy a -> a
-using x s = s x `seq` x
-
-
--- | Evaluates the second argument before the first.
--- Used to express control-oriented parallelism. The second
--- argument is usually a strategy application.
-demanding :: a -> Done -> a
-demanding = flip seq
-
-
--- | Evaluates the second argument in parallel with the first.
--- Used to express control-oriented
--- parallelism. The second argument is usually a strategy application.
-sparking :: a -> Done -> a
-sparking  = flip Parallel.par
--- Sparking should only be used
--- with a singleton sequence as it is not necessarily executed.
-
--- | A strategy corresponding to 'par': 
--- @x \`par\` e@ = @e \`using\` sPar x@.
---
--- 'sPar' has been superceded by 'sparking'.
--- Replace @e \`using\` sPar x@ with @e \`sparking\` rwhnf x@.
-{-# DEPRECATED sPar "Use sparking instead." #-}
-sPar :: a -> Strategy b
-sPar x y = x `par` ()
-
--- | A strategy corresponding to 'seq': 
--- @x \`seq\` e@ = @e \`using\` sSeq x@.
---
--- 'sSeq' has been superceded by 'demanding'. 
--- Replace @e \`using\` sSeq x@ with @e \`demanding\` rwhnf x@.
-{-# DEPRECATED sSeq "Use demanding instead." #-}
-sSeq :: a -> Strategy b
-sSeq x y = x `seq` ()
-
------------------------------------------------------------------------------
--- *			Basic Strategies				     
------------------------------------------------------------------------------
-
--- | Performs /no/ evaluation of its argument.
-r0 :: Strategy a 
-r0 x = ()
-
--- | Reduces its argument to weak head normal form.
-rwhnf :: Strategy a 
-rwhnf x = x `seq` ()  
-
-class NFData a where
-  -- | 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
-
-------------------------------------------------------------------------------
--- *                     Strategic Function Application
-------------------------------------------------------------------------------
-
-{-
-These are very
-handy when writing pipeline parallelism asa sequence of @$@, @$|@ and
-@$||@'s. There is no need of naming intermediate values in this case. The
-separation of algorithm from strategy is achieved by allowing strategies
-only as second arguments to @$|@ and @$||@.
--}
-
--- | Sequential function application. The argument is evaluated using
---   the given strategy before it is given to the function.
-($|) :: (a -> b) -> Strategy a -> a -> b
-f $| s  = \ x -> f x `demanding` s x
-
--- | Parallel function application. The argument is evaluated using
--- the given strategy, in parallel with the function application.
-($||) :: (a -> b) -> Strategy a -> a -> b
-f $|| s = \ x -> f x `sparking` s x
-
--- | Sequential function composition. The result of
--- the second function is evaluated using the given strategy, 
--- and then given to the first function.
-(.|) :: (b -> c) -> Strategy b -> (a -> b) -> (a -> c)
-(.|) f s g = \ x -> let  gx = g x 
-                    in   f gx `demanding` s gx
-
--- | Parallel function composition. The result of the second
--- function is evaluated using the given strategy,
--- in parallel with the application of the first function.
-(.||) :: (b -> c) -> Strategy b -> (a -> b) -> (a -> c)
-(.||) f s g = \ x -> let  gx = g x 
-                     in   f gx `sparking` s gx
-
--- | Sequential inverse function composition, 
--- for those who read their programs from left to right.
--- The result of the first function is evaluated using the 
--- given strategy, and then given to the second function.
-(-|) :: (a -> b) -> Strategy b -> (b -> c) -> (a -> c)
-(-|) f s g = \ x -> let  fx = f x 
-                    in   g fx `demanding` s fx
-
--- | Parallel inverse function composition,
--- for those who read their programs from left to right.
--- The result of the first function is evaluated using the 
--- given strategy, in parallel with the application of the 
--- second function.
-(-||) :: (a -> b) -> Strategy b -> (b -> c) -> (a -> c)
-(-||) f s g = \ x -> let  fx = f x 
-                     in   g fx `sparking` s fx 
-
-------------------------------------------------------------------------------
---			Marking a Strategy
-------------------------------------------------------------------------------
-
-{-
-Marking a strategy.
-
-Actually, @markStrat@  sticks a label @n@  into the sparkname  field of the
-thread executing strategy @s@. Together with a runtime-system that supports
-propagation of sparknames to the children this means that this strategy and
-all its children have  the sparkname @n@ (if the  static sparkname field in
-the @parGlobal@ annotation contains the value 1). Note, that the @SN@ field
-of starting the marked strategy itself contains the sparkname of the parent
-thread. The END event contains @n@ as sparkname.
--}
-
-#if 0
-markStrat :: Int -> Strategy a -> Strategy a 
-markStrat n s x = unsafePerformPrimIO (
-     _casm_ ``%r = set_sparkname(CurrentTSO, %0);'' n `thenPrimIO` \ z ->
-     returnPrimIO (s x))
-#endif
-
------------------------------------------------------------------------------
---			Strategy Instances and Functions		     
------------------------------------------------------------------------------
-
------------------------------------------------------------------------------
--- *	                Tuples
------------------------------------------------------------------------------
-
-{-
-We currently support up to 9-tuples. If you need longer tuples you have to 
-add the instance explicitly to your program.
--}
-
-instance (NFData a, NFData b) => NFData (a,b) where
-  rnf (x,y) = rnf x `seq` rnf y
-
-instance (NFData a, NFData b, NFData c) => NFData (a,b,c) where
-  rnf (x,y,z) = rnf x `seq` rnf y `seq` rnf z 
-
-instance (NFData a, NFData b, NFData c, NFData d) => NFData (a,b,c,d) where
-  rnf (x1,x2,x3,x4) = rnf x1 `seq` 
-		        rnf x2 `seq` 
-		        rnf x3 `seq` 
-		        rnf x4 
-
-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 `seq`
-                  rnf x2 `seq`
-                  rnf x3 `seq`
-                  rnf x4 `seq`
-                  rnf x5
-
-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 `seq`
-                  rnf x2 `seq`
-                  rnf x3 `seq`
-                  rnf x4 `seq`
-                  rnf x5 `seq`
-                  rnf x6
-
-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 `seq`
-                  rnf x2 `seq`
-                  rnf x3 `seq`
-                  rnf x4 `seq`
-                  rnf x5 `seq`
-                  rnf x6 `seq`
-                  rnf x7
-
-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 `seq`
-                  rnf x2 `seq`
-                  rnf x3 `seq`
-                  rnf x4 `seq`
-                  rnf x5 `seq`
-                  rnf x6 `seq`
-                  rnf x7 `seq`
-                  rnf x8
-
-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 `seq`
-                  rnf x2 `seq`
-                  rnf x3 `seq`
-                  rnf x4 `seq`
-                  rnf x5 `seq`
-                  rnf x6 `seq`
-                  rnf x7 `seq`
-                  rnf x8 `seq`
-                  rnf x9
-
--- | Apply two strategies to the elements of a pair sequentially
---   from left to right.
-seqPair :: Strategy a -> Strategy b -> Strategy (a,b)
-seqPair strata stratb (x,y) = strata x `seq` stratb y 
-
--- | Apply two strategies to the elements of a pair in parallel.
-parPair :: Strategy a -> Strategy b -> Strategy (a,b)
-parPair strata stratb (x,y) = strata x `par` stratb y `par` ()
--- The reason for the last 'par' is so that the strategy terminates 
--- quickly. This is important if the strategy is used as the 1st 
--- argument of a seq
-
--- | Apply three strategies to the elements of a triple in sequentially
---   from left to right.
-seqTriple :: Strategy a -> Strategy b -> Strategy c -> Strategy (a,b,c)
-seqTriple strata stratb stratc p@(x,y,z) = 
-  strata x `seq` 
-  stratb y `seq`
-  stratc z 
-
--- | Apply three strategies to the elements of a triple in parallel.
-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`
-  ()
-
------------------------------------------------------------------------------
--- 			Atomic types
------------------------------------------------------------------------------
-
-{-
-Weak head normal form and normal form are identical for integers, so the 
-default rnf is sufficient. 
--}
-instance NFData Int 
-instance NFData Integer
-instance NFData Float
-instance NFData Double
-
-instance NFData Int8
-instance NFData Int16
-instance NFData Int32
-instance NFData Int64
-
-instance NFData Word8
-instance NFData Word16
-instance NFData Word32
-instance NFData Word64
-
-instance NFDataIntegral Int
-instance NFDataOrd Int
-
---Rational and complex numbers.
-
-instance (Integral a, NFData a) => NFData (Ratio a) where
-  rnf (x:%y) = rnf x `seq` 
-               rnf y `seq`
-               ()
-
-instance (RealFloat a, NFData a) => NFData (Complex a) where
-  rnf (x:+y) = rnf x `seq` 
-	         rnf y `seq`
-               ()
-
-instance NFData Char
-instance NFData Bool
-instance NFData ()
-
------------------------------------------------------------------------------
--- 			Various library types						    
------------------------------------------------------------------------------
-
-instance NFData a => NFData (Maybe a) where
-    rnf Nothing  = ()
-    rnf (Just x) = rnf x
-
-instance (NFData a, NFData b) => NFData (Either a b) where
-    rnf (Left x)  = rnf x
-    rnf (Right y) = rnf y
-
-instance (NFData k, NFData a) => NFData (Data.Map.Map k a) where
-    rnf = rnf . Data.Map.toList
-
-instance NFData a => NFData (Data.Set.Set a) where
-    rnf = rnf . Data.Set.toList
-
-instance NFData a => NFData (Data.Tree.Tree a) where
-    rnf (Data.Tree.Node r f) = rnf r `seq` rnf f
-
-instance NFData a => NFData (Data.IntMap.IntMap a) where
-    rnf = rnf . Data.IntMap.toList
-
-instance NFData Data.IntSet.IntSet where
-    rnf = rnf . Data.IntSet.toList
-
------------------------------------------------------------------------------
--- 			Lists						    
------------------------------------------------------------------------------
-
-instance NFData a => NFData [a] where
-  rnf [] = ()
-  rnf (x:xs) = rnf x `seq` rnf xs
-
-----------------------------------------------------------------------------
--- *                   Lists: Parallel Strategies
-----------------------------------------------------------------------------
-
--- | Applies a strategy to every element of a list in parallel.
-parList :: Strategy a -> Strategy [a]
-parList strat []     = ()
-parList strat (x:xs) = strat x `par` (parList strat xs)
-
--- | Applies a strategy to the first @n@ elements of a list in parallel.
-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)
-
--- | Evaluates @n@ elements of the spine of the argument list and applies
--- the given strategy to the @n@th element (if there is one) in parallel with
--- the result. E.g. @parListNth 2 [e1, e2, e3]@ evaluates @e3@.
-parListNth :: Int -> Strategy a -> Strategy [a]
-parListNth n strat xs 
-  | null rest = ()
-  | otherwise = strat (head rest) `par` ()
-  where
-    rest = drop n xs
-
--- | Splits a list into chunks (sub-sequences) of length @n@,
--- and applies a strategy sequentially to the elements in each
--- chunk. The chunks are evaluated in parallel.
--- This is useful for increasing the grain size.
-parListChunk :: Int -> Strategy a -> Strategy [a]
-parListChunk n strat [] = ()
-parListChunk n strat xs = seqListN n strat xs `par` 
-			    parListChunk n strat (drop n xs)
-
--- | Applies a function to each element of a list and 
--- and evaluates the result list in parallel,
--- using the given strategy for each element.
-parMap :: Strategy b -> (a -> b) -> [a] -> [b]
-parMap strat f xs = map f xs `using` parList strat
-
--- | Uses 'parMap' to apply a list-valued function to each
--- element of a list in parallel, and concatenates the results.
-parFlatMap :: Strategy [b] -> (a -> [b]) -> [a] -> [b]
-parFlatMap strat f xs = concat (parMap strat f xs)
-
--- | Zips together two lists using a function,
--- and evaluates the result list in parallel.
-parZipWith :: Strategy c -> (a -> b -> c) -> [a] -> [b] -> [c]
-parZipWith strat z as bs = 
-  zipWith z as bs `using` parList strat
-
-----------------------------------------------------------------------------
--- *                     Lists: Sequential Strategies
-----------------------------------------------------------------------------
-
--- | Sequentially applies a strategy to each element of a list.
-seqList :: Strategy a -> Strategy [a]
-seqList strat []     = ()
-seqList strat (x:xs) = strat x `seq` (seqList strat xs)
-
--- | Sequentially applies a strategy to the first n elements of a list.
-{-# SPECIALISE seqListN :: Int -> Strategy b -> Strategy [b] #-}
-seqListN :: (Integral a) => a -> Strategy b -> Strategy [b]
-seqListN n strat []     = ()
-seqListN 0 strat xs     = ()
-seqListN n strat (x:xs) = strat x `seq` (seqListN (n-1) strat xs)
-
--- | Applies a strategy to the @n@th element of a list
---  (if there is one) before returning the result. 
---  E.g. @seqListNth 2 [e1, e2, e3]@ evaluates @e3@.
-seqListNth :: Int -> Strategy b -> Strategy [b]
-seqListNth n strat xs 
-  | null rest = ()
-  | otherwise = strat (head rest) 
-  where
-    rest = drop n xs
-
--- | Applies a strategy to the nth element of list when the head is demanded.
--- More precisely:
---
--- * semantics: @parBuffer n s = id :: [a] -> [a]@
---
--- * dynamic behaviour: evalutates the nth element of the list when the
--- head is demanded.
---
--- The idea is to provide a `rolling buffer' of length n.
---
--- 'parBuffer' has been added for the revised version of the strategies
--- paper and supersedes the older @fringeList@.
-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
-
-{-
- 'fringeList' implements a `rolling buffer' of length n, i.e.applies a
- strategy to the nth element of list when the head is demanded. More
- precisely:
-
-   semantics:         fringeList n s = id :: [b] -> [b]
-   dynamic behaviour: evalutates the nth element of the list when the
-		      head is demanded.
-   
- The idea is to provide a `rolling buffer' of length n.
-fringeList :: (Integral a) => a -> Strategy b -> [b] -> [b]
-fringeList n strat [] = []
-fringeList n strat (r:rs) = 
-  seqListNth n strat rs `par`
-  r:fringeList n strat rs
--}
-
-------------------------------------------------------------------------------
--- *			Arrays
-------------------------------------------------------------------------------
-instance (Ix a, NFData a, NFData b) => NFData (Array a b) where
-  rnf x = rnf (bounds x) `seq` seqList rnf (elems x) `seq` ()
-
--- | Apply a strategy to all elements of an array sequentially.
-seqArr :: (Ix b) => Strategy a -> Strategy (Array b a)
-seqArr s arr = seqList s (elems arr)
-
--- | Apply a strategy to all elements of an array in parallel.
-parArr :: (Ix b) => Strategy a -> Strategy (Array b a)
-parArr s arr = parList s (elems arr)
-
-{-# DEPRECATED Assoc "Does not belong in Control.Parallel.Strategies" #-}
-data  Assoc a b =  a := b  deriving ()
-
-instance (NFData a, NFData b) => NFData (Assoc a b) where
-  rnf (x := y) = rnf x `seq` rnf y `seq` ()
-
-------------------------------------------------------------------------------
--- *	                Some strategies specific for Lolita	
-------------------------------------------------------------------------------
-
-{-# DEPRECATED fstPairFstList "This was just an example. Write your own." #-}
-fstPairFstList :: (NFData a) => Strategy [(a,b)]
-fstPairFstList = seqListN 1 (seqPair rwhnf r0)
-
--- Some HACKs for Lolita. AFAIK force is just another name for our rnf and
--- sforce is a shortcut (definition here is identical to the one in Force.lhs)
-
-{-# DEPRECATED force, sforce "Lolita-specific hacks." #-}
-force :: (NFData a) => a -> a 
-sforce :: (NFData a) => a -> b -> b
-
-force = id $| rnf
-sforce x y = force x `seq` y
+{-# LANGUAGE BangPatterns, CPP, MagicHash, UnboxedTuples #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE RecursiveDo #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Control.Parallel.Strategies
+-- Copyright   :  (c) The University of Glasgow 2001-2010
+-- License     :  BSD-style (see the file libraries/base/LICENSE)
+--
+-- Maintainer  :  libraries@haskell.org
+-- Stability   :  experimental
+-- Portability :  portable
+--
+-- Parallel evaluation strategies, or strategies for short, provide
+-- ways to express parallel computations.  Strategies have the following
+-- key features:
+--
+--  * Strategies express /deterministic parallelism/:
+--    the result of the program is unaffected by evaluating in parallel.
+--    The parallel tasks evaluated by a strategy may have no side effects.
+--    For non-deterministic parallel programming, see "Control.Concurrent".
+--
+--  * Strategies let you separate the description of the parallelism from the
+--    logic of your program, enabling modular parallelism.  The basic idea
+--    is to build a lazy data structure representing the computation, and
+--    then write a strategy that describes how to traverse the data structure
+--    and evaluate components of it sequentially or in parallel.
+--
+--  * Strategies are /compositional/: larger strategies can be built
+--    by gluing together smaller ones.
+--
+--  * The 'Eval' monad is provided, for quickly building
+--    strategies that involve traversing structures in a regular way.
+--
+-- For API history and changes in this release, see "Control.Parallel.Strategies#history".
+
+-----------------------------------------------------------------------------
+
+module Control.Parallel.Strategies (
+         -- * The strategy type
+         Strategy
+
+         -- * Application of strategies
+       , using             -- :: a -> Strategy a -> a
+       , withStrategy      -- :: Strategy a -> a -> a
+       , usingIO           -- :: a -> Strategy a -> IO a
+       , withStrategyIO    -- :: Strategy a -> a -> IO a
+
+         -- * Composition of strategies
+       , dot               -- :: Strategy a -> Strategy a -> Strategy a
+
+         -- * Basic strategies
+       , r0                -- :: Strategy a
+       , rseq
+       , rdeepseq          -- :: NFData a => Strategy a
+       , rpar              -- :: Strategy a
+       , rparWith          -- :: Strategy a -> Strategy a
+
+         -- * Injection of sequential strategies
+       , evalSeq           -- :: Seq.Strategy a -> Strategy a
+       , SeqStrategy
+
+         -- * Strategies for traversable data types
+       , evalTraversable   -- :: Traversable t => Strategy a -> Strategy (t a)
+       , parTraversable
+       , parFmap
+
+         -- * Strategies for lists
+       , evalList          -- :: Strategy a -> Strategy [a]
+       , parList
+       , evalListN         -- :: Int -> Strategy a -> Strategy [a]
+       , parListN
+       , evalListNth       -- :: Int -> Strategy a -> Strategy [a]
+       , parListNth
+       , evalListSplitAt   -- :: Int -> Strategy [a] -> Strategy [a] -> Strategy [a]
+       , parListSplitAt
+       , parListChunk
+       , parMap
+
+         -- ** Strategies for lazy lists
+       , evalBuffer        -- :: Int -> Strategy a -> Strategy [a]
+       , parBuffer
+
+         -- * Strategies for tuples
+
+         -- | Evaluate the components of a tuple according to the
+         -- given strategies.
+
+       , evalTuple2        -- :: Strategy a -> ... -> Strategy (a,...)
+       , evalTuple3
+       , evalTuple4
+       , evalTuple5
+       , evalTuple6
+       , evalTuple7
+       , evalTuple8
+       , evalTuple9
+
+
+       -- | Evaluate the components of a tuple in parallel according to
+       -- the given strategies.
+
+       , parTuple2         -- :: Strategy a -> ... -> Strategy (a,...)
+       , parTuple3
+       , parTuple4
+       , parTuple5
+       , parTuple6
+       , parTuple7
+       , parTuple8
+       , parTuple9
+
+         -- * Strategic function application
+       , ($|)              -- :: (a -> b) -> Strategy a -> a -> b
+       , ($||)
+       , (.|)              -- :: (b -> c) -> Strategy b -> (a -> b) -> a -> c
+       , (.||)
+       , (-|)              -- :: (a -> b) -> Strategy b -> (b -> c) -> a -> c
+       , (-||)
+
+         -- * For Strategy programmers
+       , Eval              -- instances: Monad, Functor, Applicative
+       , parEval           -- :: Eval a -> Eval a
+       , runEval           -- :: Eval a -> a
+       , runEvalIO         -- :: Eval a -> IO a
+       ,
+
+    -- * API History
+
+    -- $history
+
+    -- * Backwards compatibility
+
+    -- | These functions and types are all deprecated, and will be
+    -- removed in a future release.  In all cases they have been
+    -- either renamed or replaced with equivalent functionality.
+
+    Done, demanding, sparking, (>|), (>||),
+    rwhnf, unEval,
+    seqTraverse, parTraverse,
+    seqList,
+    seqPair, parPair,
+    seqTriple, parTriple,
+
+    -- * For API completeness
+
+    -- | So that users of 'rdeepseq' aren't required to import @Control.DeepSeq@:
+    NFData
+  ) where
+
+#if defined(__MHS__) || !MIN_VERSION_base(4,8,0)
+import Data.Traversable
+#endif
+#if !MIN_VERSION_base(4,8,0)
+import Control.Applicative
+#endif
+import Control.Parallel
+import Control.DeepSeq (NFData(rnf))
+import Control.Monad.Fix (MonadFix (..))
+
+#if defined(__GLASGOW_HASKELL__) && MIN_VERSION_base(4,4,0)
+import System.IO.Unsafe (unsafeDupablePerformIO)
+import Control.Exception (evaluate)
+#else
+import System.IO.Unsafe (unsafePerformIO)
+import Control.Monad
+#endif
+
+import qualified Control.Seq
+
+#ifdef __GLASGOW_HASKELL__
+import GHC.Exts
+import GHC.IO (IO (..))
+#endif
+
+infixr 9 `dot`     -- same as (.)
+infixl 0 `using`   -- lowest precedence and associate to the left
+infixl 0 `usingIO` -- lowest precedence and associate to the left
+
+-- -----------------------------------------------------------------------------
+-- Eval monad (isomorphic to Lift monad from MonadLib 3.6.1)
+
+-- | 'Eval' is a monad that makes it easier to define parallel
+-- strategies.  It is a strict identity monad, that is, in
+--
+--  > m >>= f
+--
+-- @m@ is evaluated before the result is passed to @f@.
+--
+--  > instance Monad Eval where
+--  >   return  = Done
+--  >   m >>= k = case m of
+--  >               Done x -> k x
+--
+-- If you wanted to construct a 'Strategy' for a pair that sparked the
+-- first component in parallel and then evaluated the second
+-- component, you could write
+--
+-- > myStrat :: Strategy (a,b)
+-- > myStrat (a,b) = do { a' <- rpar a; b' <- rseq b; return (a',b') }
+--
+-- Alternatively, you could write this more compactly using the
+-- Applicative style as
+--
+-- > myStrat (a,b) = (,) <$> rpar a <*> rseq b
+--
+-- More examples, using the Applicative instance:
+--
+-- > parList :: Strategy a -> Strategy [a]
+-- > parList strat = traverse (rpar `dot` strat))
+--
+-- > evalPair :: Strategy a -> Strategy b -> Strategy (a,b)
+-- > evalPair f g (a,b) = pure (,) <$> f a <*> g b
+--
+
+#if __GLASGOW_HASKELL__ >= 702
+
+newtype Eval a = Eval {unEval_ :: IO a}
+  deriving (Functor, Applicative, Monad)
+  -- GHC 7.2.1 added the seq# and spark# primitives, that we use in
+  -- the Eval monad implementation in order to get the correct
+  -- strictness behaviour.
+
+-- | Run the evaluation.
+runEval :: Eval a -> a
+#  if MIN_VERSION_base(4,4,0)
+runEval = unsafeDupablePerformIO . unEval_
+#  else
+runEval = unsafePerformIO . unEval_
+#  endif
+
+-- | Run the evaluation in the 'IO' monad. This allows sequencing of
+-- evaluations relative to 'IO' actions.
+runEvalIO :: Eval a -> IO a
+runEvalIO = unEval_
+
+-- We don't use GND to derive MonadFix from the IO instance. The IO instance
+-- has to be very careful to ensure that lazy blackholing doesn't cause IO
+-- actions to be duplicated in case of an infinite loop. This has a small
+-- performance cost. Eval computations are always assumed to be pure, so
+-- duplicating them is okay. What about ST computations embedded in Eval ones?
+-- Those also shouldn't be a problem: the ST computations are "closed", so it's
+-- safe to duplicate them, and the RTS already takes care to avoid resuming
+-- a computation paused by an asynchronous exception in multiple threads.
+-- Lazy ST takes care of itself with noDuplicate#, so we don't really need
+-- to think about it too much.
+--
+-- Note:
+--   mfix f = let res = runEval (Lift <$> f (unLift res))
+--            in case res of Lift r -> return r
+-- data Lift a = Lift a
+instance MonadFix Eval where
+  -- Borrowed from the instance for ST
+  mfix k = Eval $ IO $ \ s ->
+    let ans       = liftEv (k r) s
+        Evret _ r = ans
+    in
+    case ans of Evret s' x -> (# s', x #)
+
+data Evret a = Evret (State# RealWorld) a
+
+-- liftEv is useful when we want a lifted result from an Eval computation. It
+-- is used to implement mfix.
+liftEv :: Eval a -> State# RealWorld -> Evret a
+liftEv (Eval (IO m)) = \s -> case m s of (# s', r #) -> Evret s' r
+
+#else
+
+data Eval a = Done a
+
+-- | Pull the result out of the monad.
+runEval :: Eval a -> a
+runEval (Done x) = x
+
+-- | Run the evaluation in the 'IO' monad. This allows sequencing of
+-- evaluations relative to 'IO' actions.
+runEvalIO :: Eval a -> IO a
+runEvalIO (Done x) = return x
+
+instance Functor Eval where
+  fmap = liftM
+
+instance Applicative Eval where
+  pure = Done
+  (<*>) = ap
+
+instance Monad Eval where
+  return = pure
+#  ifdef __GLASGOW_HASKELL__
+  Done x >>= k = lazy (k x)   -- Note: pattern 'Done x' makes '>>=' strict
+#  else
+  Done x >>= k = k x
+#  endif
+
+instance MonadFix Eval where
+  mfix f = let r = f (runEval r) in r
+
+{-# RULES "lazy Done" forall x . lazy (Done x) = Done x #-}
+
+-- The Eval monad satisfies the monad laws.
+--
+-- (1) Left identity:
+--     return x >>= f ==> Done x >>= f ==> f x
+--
+-- (2) Right identity:
+--     (i)  m >>= return =*> Done u >>= return
+--                       ==> return u
+--                       ==> Done u <*= m
+--     (ii) m >>= return =*> undefined >>= return
+--                       ==> undefined <*= m
+--
+-- (3) Associativity:
+--     (i)  (m >>= f) >>= g =*> (Done u >>= f) >>= g
+--                          ==> f u >>= g <== (\x -> f x >>= g) u
+--                                        <== Done u >>= (\x -> f x >>= g)
+--                                        <*= m >>= (\x -> f x >>= g)
+--     (ii) (m >>= f) >>= g =*> (undefined >>= f) >>= g
+--                          ==> undefined >>= g
+--                          ==> undefined <== undefined >>= (\x -> f x >>= g)
+--                                        <*= m >>= (\x -> f x >>= g)
+
+#endif
+
+
+-- -----------------------------------------------------------------------------
+-- Strategies
+
+-- | A 'Strategy' is a function that embodies a parallel evaluation strategy.
+-- The function traverses (parts of) its argument, evaluating subexpressions
+-- in parallel or in sequence.
+--
+-- A 'Strategy' may do an arbitrary amount of evaluation of its
+-- argument, but should not return a value different from the one it
+-- was passed.
+--
+-- Parallel computations may be discarded by the runtime system if the
+-- program no longer requires their result, which is why a 'Strategy'
+-- function returns a new value equivalent to the old value.  The
+-- intention is that the program applies the 'Strategy' to a
+-- structure, and then uses the returned value, discarding the old
+-- value.  This idiom is expressed by the 'using' function.
+--
+type Strategy a = a -> Eval a
+
+-- | Evaluate a value using the given 'Strategy'.
+--
+-- > x `using` s = runEval (s x)
+--
+using :: a -> Strategy a -> a
+x `using` strat = runEval (strat x)
+
+-- | Evaluate a value using the given 'Strategy'.  This is simply
+-- 'using' with the arguments reversed.
+--
+withStrategy :: Strategy a -> a -> a
+withStrategy = flip using
+
+-- | Evaluate a value using the given 'Strategy' inside the 'IO' monad.  See
+-- also 'runEvalIO'.
+--
+-- > x `usingIO` s = runEvalIO (s x)
+--
+usingIO :: a -> Strategy a -> IO a
+x `usingIO` strat = runEvalIO (strat x)
+
+-- | Evaluate a value using the given 'Strategy' inside the 'IO' monad.  This
+-- is simply 'usingIO' with the arguments reversed.
+--
+withStrategyIO :: Strategy a -> a -> IO a
+withStrategyIO = flip usingIO
+
+-- | Compose two strategies.
+--
+-- > strat2 `dot` strat1 == strat2 . withStrategy strat1
+--
+-- 'dot' is associative:
+--
+-- > (strat1 `dot` strat2) `dot` strat3 == strat1 `dot` (strat2 `dot` strat3)
+--
+-- 'r0' and 'rseq' are one-sided identities of 'dot':
+--
+-- > strat `dot` r0 == strat
+-- > strat `dot` rseq == strat
+{-# DEPRECATED dot "'dot' is an unintuitive composition operator. Use 'Control.Monad.<=<` instead." #-}
+dot :: Strategy a -> Strategy a -> Strategy a
+strat2 `dot` strat1 = strat2 . runEval . strat1
+
+-- Note [dot proofs]
+-- ~~~~~~~~~~~~~~~~~
+-- Proof of strat2 `dot` strat1 == strat2 . withStrategy strat1
+--
+--    strat2 . withStrategy strat1
+-- == \x -> strat2 (withStrategy strat1 x)
+-- == \x -> strat2 (x `using` strat1)
+-- == \x -> strat2 (runEval (strat1 x))
+-- == \x -> (strat2 . runEval . strat1) x
+-- == strat2 `dot` strat1
+--
+-- Proof of associativity
+--
+--    (strat1 `dot` strat2) `dot` strat3
+-- == (strat1 . runEval . strat2) . runEval . strat3
+-- == strat1 . runEval . strat2 . runEval . strat3
+-- == strat1 . runEval . (strat2 . runEval . strat3)
+-- == strat1 `dot` (strat2 `dot` strat3)
+
+-- | Inject a sequential strategy (i.e., coerce a sequential strategy
+-- to a general strategy).
+--
+-- Thanks to 'evalSeq', the type @'SeqStrategy' a@ is a subtype
+-- of @'Strategy' a@.
+evalSeq :: SeqStrategy a -> Strategy a
+evalSeq strat x = strat x `pseq` return x
+
+-- | A name for @Control.Seq.Strategy@, for documentation only.
+type SeqStrategy a = Control.Seq.Strategy a
+
+-- --------------------------------------------------------------------------
+-- Basic strategies (some imported from SeqStrategies)
+
+-- | 'r0' performs /no/ evaluation.
+--
+-- > r0 == evalSeq Control.Seq.r0
+--
+r0 :: Strategy a
+r0 x = return x
+
+-- Proof of r0 == evalSeq Control.Seq.r0
+--
+--    evalSeq Control.Seq.r0
+-- == \x -> Control.Seq.r0 x `pseq` return x
+-- == \x -> Control.Seq.Done `pseq` return x
+-- == \x -> return x
+-- == r0
+
+-- | 'rseq' evaluates its argument to weak head normal form.
+--
+-- > rseq == evalSeq Control.Seq.rseq
+--
+rseq :: Strategy a
+#if __GLASGOW_HASKELL__ >= 702
+rseq x = Eval (evaluate x)
+#else
+rseq x = x `seq` return x
+#endif
+-- Staged NOINLINE so we can match on rseq in RULES
+{-# NOINLINE [1] rseq #-}
+
+
+-- Proof of rseq == evalSeq Control.Seq.rseq
+--
+--    evalSeq Control.Seq.rseq
+-- == \x -> Control.Seq.rseq x `pseq` return x
+-- == \x -> (x `seq` Control.Seq.Done) `pseq` return x
+-- == \x -> x `pseq` return x
+-- == rseq
+
+-- | 'rdeepseq' fully evaluates its argument.
+--
+-- > rdeepseq == evalSeq Control.Seq.rdeepseq
+--
+rdeepseq :: NFData a => Strategy a
+rdeepseq x = do rseq (rnf x); return x
+
+-- Proof of rdeepseq == evalSeq Control.Seq.rdeepseq
+--
+--    evalSeq Control.Seq.rdeepseq
+-- == \x -> Control.Seq.rdeepseq x `pseq` return x
+-- == \x -> (x `deepseq` Control.Seq.Done) `pseq` return x
+-- == \x -> (rnf x `seq` Control.Seq.Done) `pseq` return x
+-- == \x -> rnf x `pseq` return x
+-- == rdeepseq
+
+-- | 'rpar' sparks its argument (for evaluation in parallel).
+rpar :: Strategy a
+#ifdef __GLASGOW_HASKELL__
+#if __GLASGOW_HASKELL__ >= 702
+rpar x = Eval $ IO $ \s -> spark# x s
+#else
+rpar x = case (par# x) of _ -> Done x
+#endif
+#else
+rpar x = case par x () of () -> Done x
+#endif
+{-# INLINE rpar  #-}
+
+-- | Perform a computation in parallel using a strategy.
+--
+-- @
+-- rparWith strat x
+-- @
+--
+-- will spark @strat x@. Note that @rparWith strat@ is /not/ the
+-- same as @rpar ``dot`` strat@. Specifically, @rpar ``dot`` strat@
+-- always sparks a computation to reduce the result of the
+-- strategic computation to WHNF, while @rparWith strat@ need
+-- not.
+--
+-- > rparWith r0 = r0
+-- > rparWith rpar = rpar
+-- > rparWith rseq = rpar
+--
+-- @rparWith rpar x@ creates a spark that immediately creates another
+-- spark to evaluate @x@. We consider this equivalent to @rpar@ because
+-- there isn't any real additional parallelism. However, it is always
+-- less efficient because there's a bit of extra work to create the
+-- first (useless) spark. Similarly, @rparWith r0@ creates a spark
+-- that does precisely nothing. No real parallelism is added, but there
+-- is a bit of extra work to do nothing.
+rparWith :: Strategy a -> Strategy a
+rparWith strat = parEval . strat
+
+-- | 'parEval' sparks the computation of its argument for evaluation in
+-- parallel. Unlike @'rpar' . 'runEval'@, 'parEval'
+--
+--  * does not exit the `Eval` monad
+--
+--  * does not have a built-in `rseq`, so for example @'parEval' ('r0' x)@
+--    behaves as you might expect (it creates a spark that does no
+--    evaluation).
+--
+-- It is related to 'rparWith' by the following equality:
+--
+-- > parEval . strat = rparWith strat
+--
+parEval :: Eval a -> Eval a
+-- The intermediate `Lift` box is necessary, in order to avoid a built-in
+-- `rseq` in `parEval`. In particular, we want @parEval . r0 = r0@, not
+-- @parEval . r0 = rpar@.
+parEval m = do
+  l <- rpar r
+  return (case l of Lift x -> x)
+
+  where
+    r = runEval (Lift <$> m)
+
+data Lift a = Lift a
+
+-- --------------------------------------------------------------------------
+-- Strategy combinators for Traversable data types
+
+-- | Evaluate the elements of a traversable data structure
+-- according to the given strategy.
+evalTraversable :: Traversable t => Strategy a -> Strategy (t a)
+evalTraversable = traverse
+{-# INLINE evalTraversable #-}
+
+-- | Like 'evalTraversable', but evaluates all elements in parallel.
+parTraversable :: Traversable t => Strategy a -> Strategy (t a)
+parTraversable strat = evalTraversable (rparWith strat)
+{-# INLINE parTraversable #-}
+
+-- --------------------------------------------------------------------------
+-- Strategies for lists
+
+-- | Evaluate each element of a list according to the given strategy.
+-- Equivalent to 'evalTraversable' at the list type.
+--
+-- __Warning:__ This strategy evaluates the spine of the list
+-- and thus does not work on infinite lists.
+evalList :: Strategy a -> Strategy [a]
+evalList = evalTraversable
+-- Alternative explicitly recursive definition:
+-- evalList strat []     = return []
+-- evalList strat (x:xs) = strat x >>= \x' ->
+--                         evalList strat xs >>= \xs' ->
+--                         return (x':xs')
+
+-- | Evaluate each element of a list in parallel according to given strategy.
+-- Equivalent to 'parTraversable' at the list type.
+--
+-- __Warning:__ This strategy evaluates the spine of the list
+-- and thus does not work on infinite lists.
+parList :: Strategy a -> Strategy [a]
+parList = parTraversable
+-- Alternative definition via evalList:
+-- parList strat = evalList (rparWith strat)
+
+-- | @'evaListSplitAt' n stratPref stratSuff@ evaluates the prefix
+-- (of length @n@) of a list according to @stratPref@ and the suffix
+-- according to @stratSuff@.
+evalListSplitAt :: Int -> Strategy [a] -> Strategy [a] -> Strategy [a]
+evalListSplitAt n stratPref stratSuff xs
+  = let (ys,zs) = splitAt n xs in
+    stratPref ys >>= \ys' ->
+    stratSuff zs >>= \zs' ->
+    return (ys' ++ zs')
+
+-- | Like 'evalListSplitAt', but evaluates both sublists in parallel.
+parListSplitAt :: Int -> Strategy [a] -> Strategy [a] -> Strategy [a]
+parListSplitAt n stratPref stratSuff = evalListSplitAt n (rparWith stratPref) (rparWith stratSuff)
+
+-- | Evaluate the first n elements of a list according to the given strategy.
+evalListN :: Int -> Strategy a -> Strategy [a]
+evalListN n strat = evalListSplitAt n (evalList strat) r0
+
+-- | Like 'evalListN', but evaluates the first n elements in parallel.
+parListN :: Int -> Strategy a -> Strategy [a]
+parListN n strat = evalListN n (rparWith strat)
+
+-- | Evaluate the nth element of a list (if there is such) according to
+-- the given strategy.
+-- This nth is 0-based. For example, @[1, 2, 3, 4, 5] ``using`` evalListNth 4 rseq@
+-- will eval @5@, not @4@.
+-- The spine of the list up to the nth element is evaluated as a side effect.
+evalListNth :: Int -> Strategy a -> Strategy [a]
+evalListNth n strat = evalListSplitAt n r0 (evalListN 1 strat)
+
+-- | Like 'evalListNth', but evaluates the nth element in parallel.
+parListNth :: Int -> Strategy a -> Strategy [a]
+parListNth n strat = evalListNth n (rparWith strat)
+
+-- | Divides a list into chunks, and applies the strategy
+-- @'evalList' strat@ to each chunk in parallel.
+--
+-- If the chunk size is 1 or less, 'parListChunk' is equivalent to
+-- 'parList'
+--
+-- This function may be replaced by a more
+-- generic clustering infrastructure in the future.
+--
+-- __Warning:__ This strategy evaluates the spine of the list
+-- and thus does not work on infinite lists.
+parListChunk :: Int -> Strategy a -> Strategy [a]
+parListChunk n strat
+  | n <= 1 = parList strat
+  | otherwise = go
+  where
+    go [] = pure []
+    go as = mdo
+      -- Calculate the first chunk in parallel, passing it the result
+      -- of calculating the rest
+      bs <- rpar $ runEval $ evalChunk strat more n as
+
+      -- Calculate the rest
+      more <- go (drop n as)
+      return bs
+
+-- | @evalChunk strat end n as@ uses @strat@ to evaluate the first @n@
+-- elements of @as@ (ignoring the rest) and appends @end@ to the result.
+evalChunk :: Strategy a -> [a] -> Int -> Strategy [a]
+evalChunk strat = \end ->
+  let
+    go !_n [] = pure end
+    go 0 _ = pure end
+    go n (a:as) = (:) <$> strat a <*> go (n - 1) as
+  in go
+
+-- --------------------------------------------------------------------------
+-- Convenience
+
+-- | A combination of 'parList' and 'map', encapsulating a common pattern:
+--
+-- > parMap strat f = withStrategy (parList strat) . map f
+--
+-- __Warning:__ This function evaluates the spine of the list
+-- and thus does not work on infinite lists.
+parMap :: Strategy b -> (a -> b) -> [a] -> [b]
+parMap strat f = (`using` parList strat) . map f
+
+
+-- | A generalisation of 'parMap' using  'parTraversable' and `fmap`:
+--
+-- > parFmap strat g = withStrategy (parTraversable strat) . fmap f
+--
+parFmap :: Traversable t => Strategy b -> (a -> b) -> t a -> t b
+parFmap strat f = (`using` parTraversable strat) . fmap f
+
+-- --------------------------------------------------------------------------
+-- Strategies for lazy lists
+
+-- | 'evalBuffer' is a rolling buffer strategy combinator for lazy lists.
+-- Pattern matching on the result of @evalBuffer n strat xs@ will evaluate the
+-- first @n+1@ elements of @xs@ using @strat@. Pattern matching on each
+-- additional list cons will evaluate an additional element using @strat@.
+evalBuffer :: Int -> Strategy a -> Strategy [a]
+evalBuffer n0 strat xs0 = return (ret tied (drop n0 tied))
+  where
+    -- This is the heart of the strategy. The idea is to tie the evaluation
+    -- of each cons (to WHNF) to the evaluation of its contents (according
+    -- to strat). Walking the spine of the result will thus perform
+    -- the requested Eval actions.
+    tied = foldr go [] xs0
+      where
+        go x r = runEval ((: r) <$> strat x)
+
+    ret (x : xs) (_y : ys) = x : ret xs ys
+    ret xs       _         = xs
+
+-- | 'parBuffer' is a rolling buffer strategy combinator for lazy lists.
+-- Pattern matching on the result of @parBuffer n s xs@ sparks
+-- computations to evaluate the first @n+1@ elements of @xs@ using the
+-- strategy @s@. Pattern matching on each additional list cons will
+-- spark an additional computation.
+--
+-- @parBuffer n strat = 'evalBuffer' n ('rparWith' strat)@
+parBuffer :: Int -> Strategy a -> Strategy [a]
+parBuffer n strat = evalBuffer n (rparWith strat)
+
+-- --------------------------------------------------------------------------
+-- Strategies for tuples
+
+evalTuple2 :: Strategy a -> Strategy b -> Strategy (a,b)
+evalTuple2 strat1 strat2 (x1,x2) =
+  pure (,) <*> strat1 x1 <*> strat2 x2
+
+evalTuple3 :: Strategy a -> Strategy b -> Strategy c -> Strategy (a,b,c)
+evalTuple3 strat1 strat2 strat3 (x1,x2,x3) =
+  pure (,,) <*> strat1 x1 <*> strat2 x2 <*> strat3 x3
+
+evalTuple4 :: Strategy a -> Strategy b -> Strategy c -> Strategy d -> Strategy (a,b,c,d)
+evalTuple4 strat1 strat2 strat3 strat4 (x1,x2,x3,x4) =
+  pure (,,,) <*> strat1 x1 <*> strat2 x2 <*> strat3 x3 <*> strat4 x4
+
+evalTuple5 :: Strategy a -> Strategy b -> Strategy c -> Strategy d -> Strategy e -> Strategy (a,b,c,d,e)
+evalTuple5 strat1 strat2 strat3 strat4 strat5 (x1,x2,x3,x4,x5) =
+  pure (,,,,) <*> strat1 x1 <*> strat2 x2 <*> strat3 x3 <*> strat4 x4 <*> strat5 x5
+
+evalTuple6 :: Strategy a -> Strategy b -> Strategy c -> Strategy d -> Strategy e -> Strategy f -> Strategy (a,b,c,d,e,f)
+evalTuple6 strat1 strat2 strat3 strat4 strat5 strat6 (x1,x2,x3,x4,x5,x6) =
+  pure (,,,,,) <*> strat1 x1 <*> strat2 x2 <*> strat3 x3 <*> strat4 x4 <*> strat5 x5 <*> strat6 x6
+
+evalTuple7 :: Strategy a -> Strategy b -> Strategy c -> Strategy d -> Strategy e -> Strategy f -> Strategy g -> Strategy (a,b,c,d,e,f,g)
+evalTuple7 strat1 strat2 strat3 strat4 strat5 strat6 strat7 (x1,x2,x3,x4,x5,x6,x7) =
+  pure (,,,,,,) <*> strat1 x1 <*> strat2 x2 <*> strat3 x3 <*> strat4 x4 <*> strat5 x5 <*> strat6 x6 <*> strat7 x7
+
+evalTuple8 :: Strategy a -> Strategy b -> Strategy c -> Strategy d -> Strategy e -> Strategy f -> Strategy g -> Strategy h -> Strategy (a,b,c,d,e,f,g,h)
+evalTuple8 strat1 strat2 strat3 strat4 strat5 strat6 strat7 strat8 (x1,x2,x3,x4,x5,x6,x7,x8) =
+  pure (,,,,,,,) <*> strat1 x1 <*> strat2 x2 <*> strat3 x3 <*> strat4 x4 <*> strat5 x5 <*> strat6 x6 <*> strat7 x7 <*> strat8 x8
+
+evalTuple9 :: Strategy a -> Strategy b -> Strategy c -> Strategy d -> Strategy e -> Strategy f -> Strategy g -> Strategy h -> Strategy i -> Strategy (a,b,c,d,e,f,g,h,i)
+evalTuple9 strat1 strat2 strat3 strat4 strat5 strat6 strat7 strat8 strat9 (x1,x2,x3,x4,x5,x6,x7,x8,x9) =
+  pure (,,,,,,,,) <*> strat1 x1 <*> strat2 x2 <*> strat3 x3 <*> strat4 x4 <*> strat5 x5 <*> strat6 x6 <*> strat7 x7 <*> strat8 x8 <*> strat9 x9
+
+parTuple2 :: Strategy a -> Strategy b -> Strategy (a,b)
+parTuple2 strat1 strat2 =
+  evalTuple2 (rparWith strat1) (rparWith strat2)
+
+parTuple3 :: Strategy a -> Strategy b -> Strategy c -> Strategy (a,b,c)
+parTuple3 strat1 strat2 strat3 =
+  evalTuple3 (rparWith strat1) (rparWith strat2) (rparWith strat3)
+
+parTuple4 :: Strategy a -> Strategy b -> Strategy c -> Strategy d -> Strategy (a,b,c,d)
+parTuple4 strat1 strat2 strat3 strat4 =
+  evalTuple4 (rparWith strat1) (rparWith strat2) (rparWith strat3) (rparWith strat4)
+
+parTuple5 :: Strategy a -> Strategy b -> Strategy c -> Strategy d -> Strategy e -> Strategy (a,b,c,d,e)
+parTuple5 strat1 strat2 strat3 strat4 strat5 =
+  evalTuple5 (rparWith strat1) (rparWith strat2) (rparWith strat3) (rparWith strat4) (rparWith strat5)
+
+parTuple6 :: Strategy a -> Strategy b -> Strategy c -> Strategy d -> Strategy e -> Strategy f -> Strategy (a,b,c,d,e,f)
+parTuple6 strat1 strat2 strat3 strat4 strat5 strat6 =
+  evalTuple6 (rparWith strat1) (rparWith strat2) (rparWith strat3) (rparWith strat4) (rparWith strat5) (rparWith strat6)
+
+parTuple7 :: Strategy a -> Strategy b -> Strategy c -> Strategy d -> Strategy e -> Strategy f -> Strategy g -> Strategy (a,b,c,d,e,f,g)
+parTuple7 strat1 strat2 strat3 strat4 strat5 strat6 strat7 =
+  evalTuple7 (rparWith strat1) (rparWith strat2) (rparWith strat3) (rparWith strat4) (rparWith strat5) (rparWith strat6) (rparWith strat7)
+
+parTuple8 :: Strategy a -> Strategy b -> Strategy c -> Strategy d -> Strategy e -> Strategy f -> Strategy g -> Strategy h -> Strategy (a,b,c,d,e,f,g,h)
+parTuple8 strat1 strat2 strat3 strat4 strat5 strat6 strat7 strat8 =
+  evalTuple8 (rparWith strat1) (rparWith strat2) (rparWith strat3) (rparWith strat4) (rparWith strat5) (rparWith strat6) (rparWith strat7) (rparWith strat8)
+
+parTuple9 :: Strategy a -> Strategy b -> Strategy c -> Strategy d -> Strategy e -> Strategy f -> Strategy g -> Strategy h -> Strategy i -> Strategy (a,b,c,d,e,f,g,h,i)
+parTuple9 strat1 strat2 strat3 strat4 strat5 strat6 strat7 strat8 strat9 =
+  evalTuple9 (rparWith strat1) (rparWith strat2) (rparWith strat3) (rparWith strat4) (rparWith strat5) (rparWith strat6) (rparWith strat7) (rparWith strat8) (rparWith strat9)
+
+-- --------------------------------------------------------------------------
+-- Strategic function application
+
+{-
+These are very handy when writing pipeline parallelism as a sequence of
+@$@, @$|@ and @$||@'s. There is no need of naming intermediate values
+in this case. The separation of algorithm from strategy is achieved by
+allowing strategies only as second arguments to @$|@ and @$||@.
+-}
+
+-- | Sequential function application. The argument is evaluated using
+-- the given strategy before it is given to the function.
+($|) :: (a -> b) -> Strategy a -> a -> b
+f $| s  = \x -> runEval (f <$> s x)
+
+-- | Parallel function application. The argument is evaluated using
+-- the given strategy, in parallel with the function application.
+($||) :: (a -> b) -> Strategy a -> a -> b
+f $|| s = \x -> runEval (f <$> rparWith s x)
+
+-- | Sequential function composition. The result of
+-- the second function is evaluated using the given strategy,
+-- and then given to the first function.
+(.|) :: (b -> c) -> Strategy b -> (a -> b) -> (a -> c)
+(.|) f s g = \x -> runEval (f <$> s (g x))
+
+-- | Parallel function composition. The result of the second
+-- function is evaluated using the given strategy,
+-- in parallel with the application of the first function.
+(.||) :: (b -> c) -> Strategy b -> (a -> b) -> (a -> c)
+(.||) f s g = \x -> runEval (f <$> rparWith s (g x))
+
+-- | Sequential inverse function composition,
+-- for those who read their programs from left to right.
+-- The result of the first function is evaluated using the
+-- given strategy, and then given to the second function.
+(-|) :: (a -> b) -> Strategy b -> (b -> c) -> (a -> c)
+(-|) f s g = \x -> runEval (g <$> s (f x))
+
+-- | Parallel inverse function composition,
+-- for those who read their programs from left to right.
+-- The result of the first function is evaluated using the
+-- given strategy, in parallel with the application of the
+-- second function.
+(-||) :: (a -> b) -> Strategy b -> (b -> c) -> (a -> c)
+(-||) f s g = \x -> runEval (g <$> rparWith s (f x))
+
+-- -----------------------------------------------------------------------------
+-- Old/deprecated stuff
+
+{-# DEPRECATED Done "The Strategy type is now a -> Eval a, not a -> Done" #-}
+type Done = ()
+
+{-# DEPRECATED demanding "Use 'pseq' or '$|' instead" #-}
+demanding :: a -> Done -> a
+demanding = flip pseq
+
+{-# DEPRECATED sparking "Use 'par' or '$||' instead" #-}
+sparking :: a -> Done -> a
+sparking  = flip par
+
+{-# DEPRECATED (>|) "Use 'pseq' or '$|' instead" #-}
+(>|) :: Done -> Done -> Done
+(>|) = Prelude.seq
+
+{-# DEPRECATED (>||) "Use 'par' or '$||' instead" #-}
+(>||) :: Done -> Done -> Done
+(>||) = par
+
+{-# DEPRECATED rwhnf "renamed to 'rseq'" #-}
+rwhnf :: Strategy a
+rwhnf = rseq
+
+{-# DEPRECATED seqTraverse "renamed to 'evalTraversable'" #-}
+seqTraverse :: Traversable t => Strategy a -> Strategy (t a)
+seqTraverse = evalTraversable
+
+{-# DEPRECATED parTraverse "renamed to 'parTraversable'" #-}
+parTraverse :: Traversable t => Strategy a -> Strategy (t a)
+parTraverse = parTraversable
+
+{-# DEPRECATED seqList "renamed to 'evalList'" #-}
+seqList :: Strategy a -> Strategy [a]
+seqList = evalList
+
+{-# DEPRECATED seqPair "renamed to 'evalTuple2'" #-}
+seqPair :: Strategy a -> Strategy b -> Strategy (a,b)
+seqPair = evalTuple2
+
+{-# DEPRECATED parPair "renamed to 'parTuple2'" #-}
+parPair :: Strategy a -> Strategy b -> Strategy (a,b)
+parPair = parTuple2
+
+{-# DEPRECATED seqTriple "renamed to 'evalTuple3'" #-}
+seqTriple :: Strategy a -> Strategy b -> Strategy c -> Strategy (a,b,c)
+seqTriple = evalTuple3
+
+{-# DEPRECATED parTriple "renamed to 'parTuple3'" #-}
+parTriple :: Strategy a -> Strategy b -> Strategy c -> Strategy (a,b,c)
+parTriple = parTuple3
+
+{-# DEPRECATED unEval "renamed to 'runEval'" #-}
+unEval :: Eval a -> a
+unEval = runEval
+
+{- $history #history#
+
+The strategies library has a long history.  What follows is a
+summary of how the current design evolved, and is mostly of
+interest to those who are familiar with an older version, or need
+to adapt old code to use the newer API.
+
+=== Version 1.x
+
+  The original Strategies design is described in [/Algorithm + Strategy = Parallelism/](https://www.macs.hw.ac.uk/~dsg/gph/papers/html/Strategies/strategies.html)
+  and the code was written by
+     Phil Trinder, Hans-Wolfgang Loidl, Kevin Hammond et al.
+
+=== Version 2.x
+
+Later, during work on the shared-memory implementation of
+parallelism in GHC, we discovered that the original formulation of
+Strategies had some problems, in particular it lead to space leaks
+and difficulties expressing speculative parallelism.  Details are in
+the paper [/Runtime Support for Multicore Haskell/](https://www.microsoft.com/en-us/research/wp-content/uploads/2009/09/multicore-ghc.pdf).
+
+This module has been rewritten in version 2. The main change is to
+the @'Strategy' a@ type synonym, which was previously @a -> Done@ and
+is now @a -> Eval a@.  This change helps to fix the space leak described
+in \"Runtime Support for Multicore Haskell\".  The problem is that
+the runtime will currently retain the memory referenced by all
+sparks, until they are evaluated.  Hence, we must arrange to
+evaluate all the sparks eventually, just in case they aren't
+evaluated in parallel, so that they don't cause a space leak.  This
+is why we must return a \"new\" value after applying a 'Strategy',
+so that the application can evaluate each spark created by the
+'Strategy'.
+
+The simple rule is this: you /must/ use the result of applying
+a 'Strategy' if the strategy creates parallel sparks, and you
+should probably discard the original value.  If you don't
+do this, currently it may result in a space leak.  In the
+future (GHC 6.14), it will probably result in lost parallelism
+instead, as we plan to change GHC so that unreferenced sparks
+are discarded rather than retained (we can't make this change
+until most code is switched over to this new version of
+Strategies, because code using the old verison of Strategies
+would be broken by the change in policy).
+
+The other changes in version 2.x are:
+
+  * Strategies can now be defined using a convenient Monad/Applicative
+    type, 'Eval'.  e.g. @parList s = traverse (rpar . (``using`` s))@
+
+  * 'parList' has been generalised to 'parTraverse', which works on
+    any 'Traversable' type, and similarly 'seqList' has been generalised
+    to 'seqTraverse'
+
+  * 'parList' and 'parBuffer' have versions specialised to 'rwhnf',
+    and there are transformation rules that automatically translate
+    e.g. @parList rwnhf@ into a call to the optimised version.
+
+  * 'NFData' has been moved to @Control.DeepSeq@ in the @deepseq@
+    package.  Note that since the 'Strategy' type changed, 'rnf'
+    is no longer a 'Strategy': use 'rdeepseq' instead.
+
+Version 2.1 moved 'NFData' into a separate package, @deepseq@.
+
+Version 2.2 changed the type of Strategy to @a -> Eval a@, and
+re-introduced the @r0@ strategy which was missing in version 2.1.
+
+Version 2.3 simplified the @Eval@ type, so that @Eval@ is now just
+the strict identity monad.  This change and various other
+improvements and refactorings are thanks to Patrick Maier who
+noticed that @Eval@ didn't satisfy the monad laws, and that a
+simpler version would fix that problem.
+
+(Version 2.3 was not released on Hackage.)
+
+=== Version 3.x
+
+Version 3 introduced a major overhaul of the API, to match what is
+presented in the paper
+
+  [/Seq no More: Better Strategies for Parallel Haskell/]
+  (https://simonmar.github.io/bib/papers/strategies.pdf)
+
+The major differences in the API are:
+
+ * The addition of sequential strategies ("Control.Seq") as
+   a composable means for specifying sequential evaluation.
+
+ * Changes to the naming scheme: 'rwhnf' renamed to 'rseq',
+   'seqList' renamed to 'evalList', 'seqPair' renamed to
+   'evalTuple2'.
+
+The naming scheme is now as follows:
+
+  * Basic polymorphic strategies (of type @'Strategy' a@) are called @r...@.
+    Examples: 'r0', 'rseq', 'rpar', 'rdeepseq'.
+
+  * A strategy combinator for a particular type constructor
+    or constructor class @T@ is called @evalT...@, @parT...@ or @seqT...@.
+
+  * The @seqT...@ combinators (residing in module
+     "Control.Seq") yield sequential strategies.
+     Thus, @seqT...@ combinators cannot spark, nor can the sequential
+     strategies to which they may be applied.
+     Examples: 'seqTuple2', 'seqListN', 'seqFoldable'.
+
+  * The @evalT...@ combinators do not spark themselves, yet they may
+     be applied to strategies that do spark. (They may also be applied
+     to non-sparking strategies; however, in that case the corresponding
+     @seqT...@ combinator might be a better choice.)
+     Examples: 'evalTuple2', 'evalListN', 'evalTraversable'.
+
+  * The @parT...@ combinators, which are derived from their @evalT...@
+     counterparts, do spark. They may be applied to all strategies,
+     whether sparking or not.
+     Examples: 'parTuple2', 'parListN', 'parTraversable'.
+
+  * An exception to the type driven naming scheme are 'evalBuffer' and
+     'parBuffer', which are not named after their type constructor (lists)
+     but after their function (rolling buffer of fixed size).
+-}
diff --git a/Control/Seq.hs b/Control/Seq.hs
new file mode 100644
--- /dev/null
+++ b/Control/Seq.hs
@@ -0,0 +1,204 @@
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE CPP #-}
+
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Control.Parallel.SeqStrategies
+-- Copyright   :  (c) The University of Glasgow 2001-2009
+-- License     :  BSD-style (see the file libraries/base/LICENSE)
+--
+-- Maintainer  :  libraries@haskell.org
+-- Stability   :  experimental
+-- Portability :  portable
+--
+-- Sequential strategies provide ways to compositionally specify
+-- the degree of evaluation of a data type between the extremes of
+-- no evaluation and full evaluation.
+-- Sequential strategies may be viewed as complementary to the parallel
+-- ones (see module "Control.Parallel.Strategies").
+--
+
+module Control.Seq
+       (
+         -- * The sequential strategy type
+         Strategy
+
+         -- * Application of sequential strategies
+       , using            -- :: a -> Strategy a -> a
+       , withStrategy     -- :: Strategy a -> a -> a
+
+         -- * Basic sequential strategies
+       , r0               -- :: Strategy a
+       , rseq
+       , rdeepseq         -- :: NFData a => Strategy a
+
+         -- * Sequential strategies for lists
+       , seqList          -- :: Strategy a -> Strategy [a]
+       , seqListN         -- :: Int -> Strategy a -> Strategy [a]
+       , seqListNth
+
+         -- * Sequential strategies for foldable data types
+       , seqFoldable      -- :: Foldable t => Strategy a -> Strategy (t a)
+       , seqMap           -- :: Strategy k -> Strategy v -> Strategy (Map k v)
+       , seqArray         -- :: Ix i => Strategy a -> Strategy (Array i a)
+       , seqArrayBounds   -- :: Ix i => Strategy i -> Strategy (Array i a)
+
+         -- * Sequential strategies for tuples
+
+         -- | Evaluate the components of a tuple according to the given strategies.
+         -- No guarantee is given as to the order of evaluation.
+
+       , seqTuple2        -- :: Strategy a -> ... -> Strategy (a,...)
+       , seqTuple3
+       , seqTuple4
+       , seqTuple5
+       , seqTuple6
+       , seqTuple7
+       , seqTuple8
+       , seqTuple9
+       ) where
+
+import Control.DeepSeq (NFData, deepseq)
+#if defined(__GLASGOW_HASKELL__) && MIN_VERSION_base(4,8,0)
+import Data.Foldable (toList)
+#else
+import Data.Foldable (Foldable, toList)
+#endif
+import Data.Map (Map)
+import qualified Data.Map (toList)
+#if !((__GLASGOW_HASKELL__ >= 711) && MIN_VERSION_array(0,5,1))
+import Data.Ix (Ix)
+#endif
+import Data.Array (Array)
+import qualified Data.Array (bounds, elems)
+
+infixl 0 `using`   -- lowest precedence and associate to the left
+
+-- --------------------------------------------------------------------------
+-- Sequential strategies
+
+-- | The type @'Strategy' a@ is @a -> ()@.
+-- Thus, a strategy is a function whose sole purpose it is to evaluate
+-- its argument (either in full or in part).
+type Strategy a = a -> ()
+
+-- | Evaluate a value using the given strategy.
+using :: a -> Strategy a -> a
+x `using` strat = strat x `seq` x
+
+-- | Evaluate a value using the given strategy.
+-- This is simply 'using' with arguments reversed.
+withStrategy :: Strategy a -> a -> a
+withStrategy = flip using
+
+-- --------------------------------------------------------------------------
+-- Basic sequential strategies
+
+-- | 'r0' performs /no/ evaluation.
+r0 :: Strategy a
+r0 _ = ()
+
+-- | 'rseq' evaluates its argument to weak head normal form.
+rseq :: Strategy a
+rseq x = x `seq` ()
+
+-- | 'rdeepseq' fully evaluates its argument.
+-- Relies on class 'NFData' from module "Control.DeepSeq".
+rdeepseq :: NFData a => Strategy a
+rdeepseq x = x `deepseq` ()
+
+
+-- --------------------------------------------------------------------------
+-- Sequential strategies for lists
+
+-- | Evaluate each element of a list according to the given strategy.
+-- This function is a specialisation of 'seqFoldable' to lists.
+seqList :: Strategy a -> Strategy [a]
+seqList _strat []    = ()
+seqList strat (x:xs) = strat x `seq` seqList strat xs
+-- Alternative definition via seqFoldable:
+-- seqList = seqFoldable
+
+-- | Evaluate the first n elements of a list according to the given strategy.
+seqListN :: Int -> Strategy a -> Strategy [a]
+seqListN 0  _strat _     = ()
+seqListN !_ _strat []    = ()
+seqListN !n strat (x:xs) = strat x `seq` seqListN (n-1) strat xs
+
+-- | Evaluate the nth element of a list (if there is such) according to
+-- the given strategy.
+-- The spine of the list up to the nth element is evaluated as a side effect.
+seqListNth :: Int -> Strategy a -> Strategy [a]
+seqListNth 0  strat  (x:_)  = strat x
+seqListNth !_ _strat []     = ()
+seqListNth !n strat  (_:xs) = seqListNth (n-1) strat xs
+
+
+-- --------------------------------------------------------------------------
+-- Sequential strategies for foldable data types
+
+-- | Evaluate the elements of a foldable data structure according to
+-- the given strategy.
+seqFoldable :: Foldable t => Strategy a -> Strategy (t a)
+seqFoldable strat = seqList strat . toList
+-- Alternative definition via foldl':
+-- seqFoldable strat = foldl' (const strat) ()
+
+{-# SPECIALISE seqFoldable :: Strategy a -> Strategy [a] #-}
+
+-- | Evaluate the elements of an array according to the given strategy.
+-- Evaluation of the array bounds may be triggered as a side effect.
+#if (__GLASGOW_HASKELL__ >= 711) && MIN_VERSION_array(0,5,1)
+seqArray :: Strategy a -> Strategy (Array i a)
+#else
+seqArray :: Ix i => Strategy a -> Strategy (Array i a)
+#endif
+seqArray strat = seqList strat . Data.Array.elems
+
+-- | Evaluate the bounds of an array according to the given strategy.
+#if (__GLASGOW_HASKELL__ >= 711) && MIN_VERSION_array(0,5,1)
+seqArrayBounds :: Strategy i -> Strategy (Array i a)
+#else
+seqArrayBounds :: Ix i => Strategy i -> Strategy (Array i a)
+#endif
+seqArrayBounds strat = seqTuple2 strat strat . Data.Array.bounds
+
+-- | Evaluate the keys and values of a map according to the given strategies.
+seqMap :: Strategy k -> Strategy v -> Strategy (Map k v)
+seqMap stratK stratV = seqList (seqTuple2 stratK stratV) . Data.Map.toList
+
+
+-- --------------------------------------------------------------------------
+-- Sequential strategies for tuples
+
+seqTuple2 :: Strategy a -> Strategy b -> Strategy (a,b)
+seqTuple2 strat1 strat2 (x1,x2) =
+  strat1 x1 `seq` strat2 x2
+
+seqTuple3 :: Strategy a -> Strategy b -> Strategy c -> Strategy (a,b,c)
+seqTuple3 strat1 strat2 strat3 (x1,x2,x3) =
+  strat1 x1 `seq` strat2 x2 `seq` strat3 x3
+
+seqTuple4 :: Strategy a -> Strategy b -> Strategy c -> Strategy d -> Strategy (a,b,c,d)
+seqTuple4 strat1 strat2 strat3 strat4 (x1,x2,x3,x4) =
+  strat1 x1 `seq` strat2 x2 `seq` strat3 x3 `seq` strat4 x4
+
+seqTuple5 :: Strategy a -> Strategy b -> Strategy c -> Strategy d -> Strategy e -> Strategy (a,b,c,d,e)
+seqTuple5 strat1 strat2 strat3 strat4 strat5 (x1,x2,x3,x4,x5) =
+  strat1 x1 `seq` strat2 x2 `seq` strat3 x3 `seq` strat4 x4 `seq` strat5 x5
+
+seqTuple6 :: Strategy a -> Strategy b -> Strategy c -> Strategy d -> Strategy e -> Strategy f -> Strategy (a,b,c,d,e,f)
+seqTuple6 strat1 strat2 strat3 strat4 strat5 strat6 (x1,x2,x3,x4,x5,x6) =
+  strat1 x1 `seq` strat2 x2 `seq` strat3 x3 `seq` strat4 x4 `seq` strat5 x5 `seq` strat6 x6
+
+seqTuple7 :: Strategy a -> Strategy b -> Strategy c -> Strategy d -> Strategy e -> Strategy f -> Strategy g -> Strategy (a,b,c,d,e,f,g)
+seqTuple7 strat1 strat2 strat3 strat4 strat5 strat6 strat7 (x1,x2,x3,x4,x5,x6,x7) =
+  strat1 x1 `seq` strat2 x2 `seq` strat3 x3 `seq` strat4 x4 `seq` strat5 x5 `seq` strat6 x6 `seq` strat7 x7
+
+seqTuple8 :: Strategy a -> Strategy b -> Strategy c -> Strategy d -> Strategy e -> Strategy f -> Strategy g -> Strategy h -> Strategy (a,b,c,d,e,f,g,h)
+seqTuple8 strat1 strat2 strat3 strat4 strat5 strat6 strat7 strat8 (x1,x2,x3,x4,x5,x6,x7,x8) =
+  strat1 x1 `seq` strat2 x2 `seq` strat3 x3 `seq` strat4 x4 `seq` strat5 x5 `seq` strat6 x6 `seq` strat7 x7 `seq` strat8 x8
+
+seqTuple9 :: Strategy a -> Strategy b -> Strategy c -> Strategy d -> Strategy e -> Strategy f -> Strategy g -> Strategy h -> Strategy i -> Strategy (a,b,c,d,e,f,g,h,i)
+seqTuple9 strat1 strat2 strat3 strat4 strat5 strat6 strat7 strat8 strat9 (x1,x2,x3,x4,x5,x6,x7,x8,x9) =
+  strat1 x1 `seq` strat2 x2 `seq` strat3 x3 `seq` strat4 x4 `seq` strat5 x5 `seq` strat6 x6 `seq` strat7 x7 `seq` strat8 x8 `seq` strat9 x9
diff --git a/changelog.md b/changelog.md
new file mode 100644
--- /dev/null
+++ b/changelog.md
@@ -0,0 +1,52 @@
+# Changelog for [`parallel` package](http://hackage.haskell.org/package/parallel)
+
+## 3.3.0.0  *Oct 2025*
+
+* Bump dependency bounds
+* Support MicroHs ([#81](https://github.com/haskell/parallel/pull/81))
+* Make rolling buffer strategies compositional ([#77](https://github.com/haskell/parallel/pull/77))
+* Deprecate `dot` ([#75](https://github.com/haskell/parallel/pull/75))
+* Make strategic function application operators handle strategies correctly ([#61](https://github.com/haskell/parallel/pull/61))
+* Add `parFmap` ([#53](https://github.com/haskell/parallel/pull/53))
+* Make `parListChunk` more efficient ([#45](https://github.com/haskell/parallel/issues/45))
+* Update documentation
+
+## 3.2.2.0  *Jul 2018*
+
+* Bump dependency bounds
+* Add `parEval`
+* Add a `MonadFix Eval` instance
+
+## 3.2.1.1  *Apr 2017*
+
+* Compatibility with `deepseq-1.4.3`
+* Minor documentation clarifications
+
+## 3.2.1.0  *Jan 2016*
+
+* Support `base-4.9.0.0`
+* Add `{-# NOINLINE[1] rseq #-}` to make the `RULE` more robust
+* Fix broken links to papers in Haddock
+* Make `rpar` type signature consistent with `rseq` via type synonym
+* Drop redundant `Ix`-constraint on `seqArray`/`seqArrayBounds` for GHC >= 8.0
+
+## 3.2.0.6  *Dec 2014*
+
+* Make `-Wall` message free for all supported `base` versions
+
+## 3.2.0.5  *Dec 2014*
+
+* Support `base-4.8.0.0`/`deepseq-1.4.0.0` (and thus GHC 7.10)
+
+## 3.2.0.4  *Nov 2013*
+
+* Update package description to Cabal 1.10 format
+* Add support for GHC 7.8
+* Drop support for GHCs older than GHC 7.0.1
+* Add NOINLINE pragmas to `parBuffer`, `parList`, and `evalBuffer`
+  to make RULEs more likely to fire
+
+## Older versions
+
+* This package has a long history which is described in the Haddock documentation
+  in the ["API History" section](./docs/Control-Parallel-Strategies.html#history)
diff --git a/parallel.cabal b/parallel.cabal
--- a/parallel.cabal
+++ b/parallel.cabal
@@ -1,23 +1,70 @@
-name:		parallel
-version:	1.1.0.1
-license:	BSD3
-license-file:	LICENSE
-maintainer:	libraries@haskell.org
-synopsis:	parallel programming library
+cabal-version:  >=1.10
+name:           parallel
+version:        3.3.0.0
+-- NOTE: Don't forget to update ./changelog.md
+license:        BSD3
+license-file:   LICENSE
+maintainer:     libraries@haskell.org
+bug-reports:    https://github.com/haskell/parallel/issues
+synopsis:       Parallel programming library
+category:       Control, Parallelism
+build-type:     Simple
+
+tested-with:
+  GHC == 9.12.2
+  GHC == 9.10.1
+  GHC == 9.8.4
+  GHC == 9.6.7
+  GHC == 9.4.8
+  GHC == 9.2.8
+  GHC == 9.0.2
+  GHC == 8.10.7
+  GHC == 8.8.4
+  GHC == 8.6.5
+  GHC == 8.4.4
+  GHC == 8.2.2
+  GHC == 8.0.2
+  MHS
+
 description:
     This package provides a library for parallel programming.
-build-type:     Simple
-cabal-version:  >=1.2
+    .
+    For documentation, start from the "Control.Parallel.Strategies"
+    module below.
+    .
+    For more tutorial documentation, see the book <https://simonmar.github.io/pages/pcph.html Parallel and Concurrent Programming in Haskell>.
+    .
+    To understand the principles behind the library, see
+    <https://simonmar.github.io/bib/papers/strategies.pdf Seq no more: Better Strategies for Parallel Haskell>.
 
-library {
-  exposed-modules:
+
+extra-source-files: changelog.md
+
+source-repository head
+    type:     git
+    location: https://github.com/haskell/parallel.git
+
+library
+    default-language: Haskell2010
+    other-extensions:
+        BangPatterns
+        CPP
+        MagicHash
+        UnboxedTuples
+
+    exposed-modules:
+        Control.Seq
         Control.Parallel
         Control.Parallel.Strategies
-  extensions:	CPP
-  build-depends: base >= 3, containers, array
 
-  if impl(ghc >= 6.11) {
-    -- To improve parallel performance:
-    ghc-options: -feager-blackholing
-  }
-}
+    build-depends:
+        array      >= 0.3 && < 0.6,
+        base       >= 4.3 && < 4.22,
+        containers >= 0.4 && < 0.9,
+        deepseq    >= 1.1 && < 1.6
+
+    ghc-options: -Wall
+
+    if impl(ghc >= 6.11)
+        -- To improve parallel performance:
+        ghc-options: -feager-blackholing
