packages feed

speculation 0.8.0.2 → 0.8.1.0

raw patch · 8 files changed

+432/−69 lines, 8 filesdep +ghc-primPVP ok

version bump matches the API change (PVP)

Dependencies added: ghc-prim

API changes (from Hackage documentation)

+ Data.List.Speculation: scan :: (Monoid m, Eq m) => (Int -> m) -> [m] -> [m]
+ Data.List.Speculation: scanBy :: (Monoid m) => (m -> m -> Bool) -> (Int -> m) -> [m] -> [m]
+ Data.List.Speculation: scanMap :: (Monoid m, Eq m) => (Int -> m) -> (a -> m) -> [a] -> [m]
+ Data.List.Speculation: scanMapBy :: (Monoid m) => (m -> m -> Bool) -> (Int -> m) -> (a -> m) -> [a] -> [m]
+ Data.List.Speculation: scanl :: (Eq b) => (Int -> b) -> (b -> a -> b) -> b -> [a] -> [b]
+ Data.List.Speculation: scanl1 :: (Eq a) => (Int -> a) -> (a -> a -> a) -> [a] -> [a]
+ Data.List.Speculation: scanl1By :: (a -> a -> Bool) -> (Int -> a) -> (a -> a -> a) -> [a] -> [a]
+ Data.List.Speculation: scanlBy :: (b -> b -> Bool) -> (Int -> b) -> (b -> a -> b) -> b -> [a] -> [b]
+ Data.List.Speculation: scanr :: (Eq b) => (Int -> b) -> (a -> b -> b) -> b -> [a] -> [b]
+ Data.List.Speculation: scanr1 :: (Eq a) => (Int -> a) -> (a -> a -> a) -> [a] -> [a]
+ Data.List.Speculation: scanr1By :: (a -> a -> Bool) -> (Int -> a) -> (a -> a -> a) -> [a] -> [a]
+ Data.List.Speculation: scanrBy :: (b -> b -> Bool) -> (Int -> b) -> (a -> b -> b) -> b -> [a] -> [b]
+ Data.Traversable.Speculation: instance Applicative (IntAccumL s)
+ Data.Traversable.Speculation: instance Applicative (IntAccumR s)
+ Data.Traversable.Speculation: instance Functor (IntAccumL s)
+ Data.Traversable.Speculation: instance Functor (IntAccumR s)
+ Data.Traversable.Speculation: mapAccumL :: (Traversable t, Eq a, Eq c) => (Int -> a) -> (a -> b -> (a, c)) -> a -> t b -> (a, t c)
+ Data.Traversable.Speculation: mapAccumLBy :: (Traversable t) => (a -> a -> Bool) -> (Int -> a) -> (a -> b -> (a, c)) -> a -> t b -> (a, t c)
+ Data.Traversable.Speculation: mapAccumR :: (Traversable t, Eq a, Eq c) => (Int -> a) -> (a -> b -> (a, c)) -> a -> t b -> (a, t c)
+ Data.Traversable.Speculation: mapAccumRBy :: (Traversable t) => (a -> a -> Bool) -> (Int -> a) -> (a -> b -> (a, c)) -> a -> t b -> (a, t c)

Files

CHANGELOG.markdown view
@@ -1,3 +1,8 @@+/0.8.1/:+ * Added Data.List.Foldable+ * Added Data.Traversable.Foldable+ * Fixed an off-by-one error in the arguments to the speculative fold estimators+ /0.8.0.2/:   * changed tests and benchmarks to not build by default to work around corruption in the hackage db
Control/Concurrent/Speculation.hs view
@@ -1,6 +1,6 @@ {-# LANGUAGE CPP, BangPatterns, DeriveDataTypeable #-} module Control.Concurrent.Speculation-    ( +    (     -- * Speculative application       spec     , spec'@@ -21,6 +21,7 @@     ) where  import Control.Concurrent.STM+import Control.Concurrent.Speculation.Internal (returning) import Control.Parallel (par) import Control.Monad (liftM2, unless) import Data.Function (on)@@ -30,8 +31,8 @@ import Foreign (sizeOf) import Unsafe.Coerce (unsafeCoerce) -- dynamic pointer tagging is present on this platform-#define TAGGED -#endif +#define TAGGED+#endif  -- * Basic speculation @@ -39,7 +40,7 @@ -- -- Furthermore, if the argument has already been evaluated, we avoid sparking the parallel computation at all. ----- If a good guess at the value of @a@ is available, this is one way to induce parallelism in an otherwise sequential task. +-- If a good guess at the value of @a@ is available, this is one way to induce parallelism in an otherwise sequential task. -- -- However, if the guess isn\'t available more cheaply than the actual answer, then this saves no work and if the guess is -- wrong, you risk evaluating the function twice.@@ -51,7 +52,7 @@ -- > [---- f g ----] -- >    [----- a -----] -- > [-- spec g f a --]--- +-- -- The worst-case timeline looks like: -- -- > [---- f g ----]@@ -65,7 +66,7 @@ -- >              [---- f a ----]  spec :: Eq a => a -> (a -> b) -> a -> b-spec = specBy (==) +spec = specBy (==) {-# INLINE spec #-}  -- | Unlike 'spec', this version does not check to see if the argument has already been evaluated. This can save@@ -84,12 +85,12 @@  -- | 'spec'' with a user defined comparison function specBy' :: (a -> a -> Bool) -> a -> (a -> b) -> a -> b-specBy' cmp guess f a = -    speculation `par` +specBy' cmp guess f a =+    speculation `par`         if cmp guess a         then speculation         else f a-    where +    where         speculation = f guess {-# INLINE specBy' #-} @@ -105,12 +106,12 @@  -- * STM-based speculation --- | @'specSTM' g f a@ evaluates @f g@ while forcing @a@, if @g == a@ then @f g@ is returned. Otherwise the side-effects +-- | @'specSTM' g f a@ evaluates @f g@ while forcing @a@, if @g == a@ then @f g@ is returned. Otherwise the side-effects -- of the current STM transaction are rolled back and @f a@ is evaluated.---   +-- -- If the argument @a@ is already evaluated, we don\'t bother to perform @f g@ at all. ----- If a good guess at the value of @a@ is available, this is one way to induce parallelism in an otherwise sequential task. +-- If a good guess at the value of @a@ is available, this is one way to induce parallelism in an otherwise sequential task. -- -- However, if the guess isn\'t available more cheaply than the actual answer then this saves no work, and if the guess is -- wrong, you risk evaluating the function twice.@@ -125,10 +126,10 @@ -- -- The worst-case timeline looks like: ----- > [------ f g ------] +-- > [------ f g ------] -- >     [------- a -------] -- >                       [-- rollback --]--- >                                      [------ f a ------]     +-- >                                      [------ f a ------] -- > [------------------ spec g f a ------------------------] -- -- Compare these to the timeline of @f $! a@:@@ -148,8 +149,8 @@  -- | 'specSTM' using a user defined comparison function specBySTM :: (a -> a -> STM Bool) -> STM a -> (a -> STM b) -> a -> STM b-specBySTM cmp guess f a -    | unsafeIsEvaluated a = f a +specBySTM cmp guess f a+    | unsafeIsEvaluated a = f a     | otherwise   = specBySTM' cmp guess f a {-# INLINE specBySTM #-} @@ -159,11 +160,11 @@     guess <- mguess     result <- f guess     -- rendezvous with a-    matching <- cmp guess a -    unless matching retry +    matching <- cmp guess a+    unless matching retry     return result-  `orElse` -    f a +  `orElse`+    f a {-# INLINE specBySTM' #-}  -- | @'specBySTM' . 'on' (==)@@@ -193,6 +194,3 @@ unsafeIsEvaluated a = unsafeGetTagBits a /= 0 {-# INLINE unsafeIsEvaluated #-} -returning :: Monad m => (a -> b -> c) -> a -> b -> m c-returning f a b = return (f a b)-{-# INLINE returning #-}
+ Control/Concurrent/Speculation/Internal.hs view
@@ -0,0 +1,53 @@+module Control.Concurrent.Speculation.Internal +    ( Acc(..)+    , extractAcc+    , MaybeAcc(..)+    , fromMaybeAcc+    , errorEmptyStructure+    , returning+    ) where++import Data.Foldable+import Data.Traversable+import Control.Applicative++-- comonad!+data Acc a = Acc {-# UNPACK #-} !Int a++instance Functor Acc where+    fmap f (Acc n a) = Acc n (f a)++instance Foldable Acc where+    foldMap = foldMapDefault++instance Traversable Acc where+    traverse f (Acc n a) = Acc n <$> f a++extractAcc :: Acc a -> a+extractAcc (Acc _ a) = a+{-# INLINE extractAcc #-}++data MaybeAcc a = JustAcc {-# UNPACK #-} !Int a | NothingAcc++instance Functor MaybeAcc where+    fmap f (JustAcc n a) = JustAcc n (f a)+    fmap _ NothingAcc = NothingAcc++instance Foldable MaybeAcc where+    foldMap = foldMapDefault++instance Traversable MaybeAcc where+    traverse f (JustAcc n a) = JustAcc n <$> f a+    traverse _ NothingAcc    = pure NothingAcc++fromMaybeAcc :: a -> MaybeAcc a -> a+fromMaybeAcc _ (JustAcc _ a) = a+fromMaybeAcc a _ = a+{-# INLINE fromMaybeAcc #-}++errorEmptyStructure :: String -> a+errorEmptyStructure f = error $ f ++ ": error empty structure"++returning :: Monad m => (a -> b -> c) -> a -> b -> m c+returning f a b = return (f a b)+{-# INLINE returning #-}
Data/Foldable/Speculation.hs view
@@ -56,6 +56,7 @@ import qualified Data.Foldable as Foldable import Control.Concurrent.STM import Control.Concurrent.Speculation+import Control.Concurrent.Speculation.Internal import Control.Applicative import Control.Monad hiding (mapM_, msum, forM_, sequence_) @@ -104,7 +105,7 @@ foldrBy :: Foldable f => (b -> b -> Bool) -> (Int -> b) -> (a -> b -> b) -> b -> f a -> b foldrBy cmp g f z = extractAcc . Foldable.foldr mf (Acc 0 z)   where -    mf a (Acc n b) = let n' = n + 1 in Acc n' (specBy' cmp (g n') (f a) b)+    mf a (Acc n b) = Acc (n + 1) (specBy' cmp (g n) (f a) b) {-# INLINE foldrBy #-}  foldlM :: (Foldable f, Monad m, Eq (m b)) => (Int -> m b) -> (b -> a -> m b) -> m b -> f a -> m b@@ -116,9 +117,8 @@   where     go mia b = do       Acc n a <- mia-      let !n' = n + 1-      a' <- specBy' cmp (g n') (>>= (`f` b)) (return a)-      return (Acc n' a')+      a' <- specBy' cmp (g n) (>>= (`f` b)) (return a)+      return (Acc (n + 1) a') {-# INLINE foldlByM #-}  foldrM :: (Foldable f, Monad m, Eq (m b)) => (Int -> m b) -> (a -> b -> m b) -> m b -> f a -> m b@@ -130,9 +130,8 @@   where     go a mib = do       Acc n b <- mib-      let !n' = n + 1-      b' <- specBy' cmp (g n') (>>= f a) (return b)-      return (Acc n' b')+      b' <- specBy' cmp (g n) (>>= f a) (return b)+      return (Acc (n + 1) b') {-# INLINE foldrByM #-}  foldlSTM :: (Foldable f, Eq a) => (Int -> STM a) -> (a -> b -> STM a) -> STM a -> f b -> STM a@@ -144,9 +143,8 @@   where     go mia b = do       Acc n a <- mia-      let !n' = n + 1-      a' <- specBySTM' cmp (g n') (`f` b) a-      return (Acc n' a')+      a' <- specBySTM' cmp (g n) (`f` b) a+      return (Acc (n + 1) a') {-# INLINE foldlBySTM #-}  foldrSTM :: (Foldable f, Eq b) => (Int -> STM b) -> (a -> b -> STM b) -> STM b -> f a -> STM b@@ -158,21 +156,10 @@   where     go a mib = do       Acc n b <- mib-      let !n' = n + 1-      b' <- specBySTM' cmp (g n') (f a) b-      return (Acc n' b')+      b' <- specBySTM' cmp (g n) (f a) b+      return (Acc (n + 1) b') {-# INLINE foldrBySTM #-} -{--foldrSTMBy cmp g f z xs = liftM extractAcc . Foldable.foldl mf return xs (Acc 0 z)-  where-    mf h t = do-        Acc n t' <- t-        let !n' = n + 1 -        specSTMBy' cmp (g n') (flip f h >=> t) -        ...--}- -- | Given a valid estimator @g@, @'foldl' g f z xs@ yields the same answer as @'foldl'' f z xs@. -- -- @g n@ should supply an estimate of the value returned from folding over the first @n@ elements of the container.@@ -187,7 +174,7 @@ foldlBy  :: Foldable f => (b -> b -> Bool) -> (Int -> b) -> (b -> a -> b) -> b -> f a -> b foldlBy cmp g f z = extractAcc . Foldable.foldl mf (Acc 0 z)   where-    mf (Acc n a) b = let n' = n + 1 in Acc n' (specBy' cmp (g n') (`f` b) a)+    mf (Acc n a) b = Acc (n + 1) (specBy' cmp (g n) (`f` b) a) {-# INLINE foldlBy #-}  foldr1 :: (Foldable f, Eq a) => (Int -> a) -> (a -> a -> a) -> f a -> a@@ -198,7 +185,7 @@ foldr1By cmp g f xs = fromMaybeAcc (errorEmptyStructure "foldr1")                                    (Foldable.foldr mf NothingAcc xs)   where-    mf a (JustAcc n b) = let n' = n + 1 in JustAcc n' (specBy' cmp (g n') (f a) b)+    mf a (JustAcc n b) = JustAcc (n + 1) (specBy' cmp (g n) (f a) b)     mf a NothingAcc = JustAcc 1 a {-# INLINE foldr1By #-} @@ -210,7 +197,7 @@ foldl1By cmp g f xs = fromMaybeAcc (errorEmptyStructure "foldl1")                                (Foldable.foldl mf NothingAcc xs)   where-    mf (JustAcc n a) b = let n' = n + 1 in JustAcc n' (specBy' cmp (g n') (`f` b) a)+    mf (JustAcc n a) b = JustAcc (n + 1) (specBy' cmp (g n) (`f` b) a)     mf NothingAcc b    = JustAcc 1 b {-# INLINE foldl1By #-} @@ -405,21 +392,3 @@ findBy :: Foldable t => (Maybe a -> Maybe a -> Bool) -> (Int -> Maybe a) -> (a -> Bool) -> t a -> Maybe a  findBy cmp g p = getFirst . foldMapBy (on cmp getFirst) (First . g) (\x -> if p x then First (Just x) else First (Nothing)) -data Acc a = Acc {-# UNPACK #-} !Int a--extractAcc :: Acc a -> a-extractAcc (Acc _ a) = a -{-# INLINE extractAcc #-}--data MaybeAcc a = JustAcc {-# UNPACK #-} !Int a | NothingAcc--fromMaybeAcc :: a -> MaybeAcc a -> a -fromMaybeAcc _ (JustAcc _ a) = a-fromMaybeAcc a _ = a-{-# INLINE fromMaybeAcc #-}--errorEmptyStructure :: String -> a-errorEmptyStructure f = error $ f ++ ": error empty structure"--returning :: Monad m => (a -> b -> c) -> a -> b -> m c-returning f a b = return (f a b)
+ Data/List/Speculation.hs view
@@ -0,0 +1,173 @@+{-# LANGUAGE BangPatterns #-}+module Data.List.Speculation +    ( +    -- * Speculative scans+      scan, scanBy+    , scanMap, scanMapBy+    , scanr, scanrBy+    , scanl, scanlBy+    , scanr1, scanr1By+    , scanl1, scanl1By+    {-+    -- ** Speculative monadic scans+    , scanrM, scanrByM+    , scanlM, scanlByM+    -- * Speculative transactional monadic scans+    , scanrSTM, scanrBySTM+    , scanlSTM, scanlBySTM+    -}+    ) where+++import Prelude hiding +    (foldl, foldl1, foldr, foldr1+    , any, all, and, or, mapM_, sequence_+    , elem, notElem, sum, product+    , minimum, maximum, concat, concatMap+    , scanr, scanl, scanr1, scanl1+    )++import Data.Monoid+import qualified Data.List as List++import Control.Concurrent.Speculation+import Control.Concurrent.Speculation.Internal++scan :: (Monoid m, Eq m) => (Int -> m) -> [m] -> [m]+scan = scanBy (==)+{-# INLINE scan #-}++-- | 'scan' using 'specBy'+scanBy :: Monoid m => (m -> m -> Bool) -> (Int -> m) -> [m] -> [m]+scanBy cmp g = scanrBy cmp g mappend mempty+{-# INLINE scanBy #-}++-- | Given a valid estimator @g@, @'scanMap' g f xs@ yields the same answer as @'scanMap' f xs@.+-- +-- @g n@ should supply an estimate of the value of the monoidal summation over the last @n@ elements of the container.+-- +-- If @g n@ is accurate a reasonable percentage of the time and faster to compute than the scan, then this can+-- provide increased opportunities for parallelism.++scanMap :: (Monoid m, Eq m) => (Int -> m) -> (a -> m) -> [a] -> [m]+scanMap = scanMapBy (==)+{-# INLINE scanMap #-}++scanMapBy :: Monoid m => (m -> m -> Bool) -> (Int -> m) -> (a -> m) -> [a] -> [m]+scanMapBy cmp g f = scanrBy cmp g (mappend . f) mempty+{-# INLINE scanMapBy #-}++-- | Given a valid estimator @g@, @'scanr' g f z xs@ yields the same answer as @'scanr'' f z xs@.+--+-- @g n@ should supply an estimate of the value returned from scanning over the last @n@ elements of the container.+--+-- If @g n@ is accurate a reasonable percentage of the time and faster to compute than the scan, then this can+-- provide increased opportunities for parallelism.++scanr :: Eq b => (Int -> b) -> (a -> b -> b) -> b -> [a] -> [b]+scanr = scanrBy (==)+{-# INLINE scanr #-}++scanrBy :: (b -> b -> Bool) -> (Int -> b) -> (a -> b -> b) -> b -> [a] -> [b]+scanrBy cmp g f z = map extractAcc . List.scanr mf (Acc 0 z)+  where +    mf a (Acc n b) = let n' = n + 1 in Acc n' (specBy' cmp (g n') (f a) b)+{-# INLINE scanrBy #-}++{-+scanlM :: (Monad m, Eq (m b)) => (Int -> m b) -> (b -> a -> m b) -> m b -> [a] -> m [b]+scanlM = scanlByM (==)+{-# INLINE scanlM #-}++scanlByM ::  Monad m => (m b -> m b -> Bool) -> (Int -> m b) -> (b -> a -> m b) -> m b -> [a] -> m [b]+scanlByM  cmp g f mz = liftM (map extractAcc) . List.scanl go (liftM (map (Acc 0)) mz) +  where+    go mia b = do+      Acc n a <- mia+      let !n' = n + 1+      a' <- specBy' cmp (g n') (>>= (`f` b)) (return a)+      return (Acc n' a')+{-# INLINE scanlByM #-}++scanrM :: (Monad m, Eq (m b)) => (Int -> m b) -> (a -> b -> m b) -> m b -> [a] -> m [b]+scanrM = scanrByM (==)+{-# INLINE scanrM #-}++scanrByM :: Monad m => (m b -> m b -> Bool) -> (Int -> m b) -> (a -> b -> m b) -> m b -> [a] -> m [b]+scanrByM cmp g f mz = liftM (map extractAcc) . List.scanr go (liftM (map (Acc 0)) mz) +  where+    go a mib = do+      Acc n b <- mib+      let !n' = n + 1+      b' <- specBy' cmp (g n') (>>= f a) (return b)+      return (Acc n' b')+{-# INLINE scanrByM #-}++scanlSTM :: Eq a => (Int -> STM a) -> (a -> b -> STM a) -> STM a -> [b] -> STM [a]+scanlSTM = scanlBySTM (returning (==))+{-# INLINE scanlSTM #-}++scanlBySTM :: (a -> a -> STM Bool) -> (Int -> STM a) -> (a -> b -> STM a) -> STM a -> [b] -> STM [a]+scanlBySTM cmp g f mz = liftM (map extractAcc) . List.scanl go (liftM (Acc 0) mz)+  where+    go mia b = do+      Acc n a <- mia+      let !n' = n + 1+      a' <- specBySTM' cmp (g n') (`f` b) a+      return (Acc n' a')+{-# INLINE scanlBySTM #-}++scanrSTM :: Eq b => (Int -> STM b) -> (a -> b -> STM b) -> STM b -> [a] -> STM [b]+scanrSTM = scanrBySTM (returning (==))+{-# INLINE scanrSTM #-}++scanrBySTM :: (b -> b -> STM Bool) -> (Int -> STM b) -> (a -> b -> STM b) -> STM b -> [a] -> STM [b]+scanrBySTM cmp g f mz = liftM (map extractAcc) . List.scanr go (liftM (Acc 0) mz)+  where+    go a mib = do+      Acc n b <- mib+      let !n' = n + 1+      b' <- specBySTM' cmp (g n') (f a) b+      return (Acc n' b')+{-# INLINE scanrBySTM #-}++-- | Given a valid estimator @g@, @'scanl' g f z xs@ yields the same answer as @'scanl'' f z xs@.+--+-- @g n@ should supply an estimate of the value returned from scaning over the first @n@ elements of the container.+--+-- If @g n@ is accurate a reasonable percentage of the time and faster to compute than the scan, then this can+-- provide increased opportunities for parallelism.+-}++scanl  :: Eq b => (Int -> b) -> (b -> a -> b) -> b -> [a] -> [b]+scanl = scanlBy (==) +{-# INLINE scanl #-}++scanlBy  :: (b -> b -> Bool) -> (Int -> b) -> (b -> a -> b) -> b -> [a] -> [b]+scanlBy cmp g f z = map extractAcc . List.scanl mf (Acc 0 z)+  where+    mf (Acc n a) b = let n' = n + 1 in Acc n' (specBy' cmp (g n') (`f` b) a)+{-# INLINE scanlBy #-}++scanr1 :: Eq a => (Int -> a) -> (a -> a -> a) -> [a] -> [a]+scanr1 = scanr1By (==) +{-# INLINE scanr1 #-}++scanr1By :: (a -> a -> Bool) -> (Int -> a) -> (a -> a -> a) -> [a] -> [a]+scanr1By cmp g f xs = map (fromMaybeAcc undefined) $ List.scanr mf NothingAcc xs+  where+    mf a (JustAcc n b) = let n' = n + 1 in JustAcc n' (specBy' cmp (g n') (f a) b)+    mf a NothingAcc = JustAcc 1 a+{-# INLINE scanr1By #-}++scanl1 :: Eq a => (Int -> a) -> (a -> a -> a) -> [a] -> [a]+scanl1 = scanl1By (==)+{-# INLINE scanl1 #-}++scanl1By :: (a -> a -> Bool) -> (Int -> a) -> (a -> a -> a) -> [a] -> [a]+scanl1By cmp g f xs = map (fromMaybeAcc undefined) $ List.scanl mf NothingAcc xs+  where+    mf (JustAcc n a) b = let n' = n + 1 in JustAcc n' (specBy' cmp (g n') (`f` b) a)+    mf NothingAcc b    = JustAcc 1 b+{-# INLINE scanl1By #-}+
+ Data/Traversable/Speculation.hs view
@@ -0,0 +1,117 @@+{-# LANGUAGE MagicHash, Rank2Types, UnboxedTuples #-}+module Data.Traversable.Speculation+    ( mapAccumL, mapAccumLBy+    , mapAccumR, mapAccumRBy+    ) where++import GHC.Prim+import GHC.Types+import Data.Traversable (Traversable)+import qualified Data.Traversable as Traversable+import Control.Applicative+import Control.Concurrent.Speculation++data IntAccumL s a = IntAccumL (Int# -> s -> (# Int#, s, a #))++runIntAccumL :: IntAccumL s a -> Int -> s -> (s, a)+runIntAccumL (IntAccumL m) (I# i) s = case m i s of+    (# _, s1, a #) -> (s1, a)++instance Functor (IntAccumL s) where+    fmap f (IntAccumL m) = IntAccumL  (\i s -> case m i s of+        (# i1, s1, a #) -> (# i1, s1, f a #))++instance Applicative (IntAccumL s) where+    pure a = IntAccumL (\i s -> (# i, s, a #))+    IntAccumL mf <*> IntAccumL ma = IntAccumL (\i s ->+        case mf i s of +            (# i1, s1, f #) ->+                case ma i1 s1 of +                    (# i2, s2, a #) -> (# i2, s2, f a #))+    +mapAccumL :: (Traversable t, Eq a, Eq c) => (Int -> a) -> (a -> b -> (a, c)) -> a -> t b -> (a, t c)+mapAccumL = mapAccumLBy (==)++mapAccumLBy :: Traversable t => (a -> a -> Bool) -> (Int -> a) -> (a -> b -> (a, c)) -> a -> t b -> (a, t c)+mapAccumLBy cmp g f z xs = runIntAccumL (Traversable.traverse go xs) 0 z+  where+    go b = IntAccumL (\n a -> +            let ~(a', c) = specBy' cmp (g (I# n)) (`f` b) a+            in (# n +# 1#, a', c #))++data IntAccumR s a = IntAccumR (Int# -> s -> (# Int#, s, a #))++runIntAccumR :: IntAccumR s a -> Int -> s -> (s, a)+runIntAccumR (IntAccumR m) (I# i) s = case m i s of+    (# _, s1, a #) -> (s1, a)++instance Functor (IntAccumR s) where+    fmap f (IntAccumR m) = IntAccumR  (\i s -> case m i s of+        (# i1, s1, a #) -> (# i1, s1, f a #))++instance Applicative (IntAccumR s) where+    pure a = IntAccumR (\i s -> (# i, s, a #))+    IntAccumR mf <*> IntAccumR ma = IntAccumR (\i s ->+        case ma i s of +            (# i1, s1, a #) ->+                case mf i1 s1 of +                    (# i2, s2, f #) -> (# i2, s2, f a #))++mapAccumR :: (Traversable t, Eq a, Eq c) => (Int -> a) -> (a -> b -> (a, c)) -> a -> t b -> (a, t c)+mapAccumR = mapAccumRBy (==)++mapAccumRBy :: Traversable t => (a -> a -> Bool) -> (Int -> a) -> (a -> b -> (a, c)) -> a -> t b -> (a, t c)+mapAccumRBy cmp g f z xs = runIntAccumR (Traversable.traverse go xs) 0 z+  where+    go b = IntAccumR (\n a -> +            let ~(a', c) = specBy' cmp (g (I# n)) (`f` b) a+            in (# n +# 1#, a', c #))++{-+traverse :: (Traversable t, Applicative f, Eq (f b)) => (Int -> f b) -> (a -> f b) -> t a -> f (t b)+traverse = traverseBy (==)++traverseBy :: (Traversable t, Applicative f) => (Int -> f b) -> (a -> f b) -> t a -> f (t b)+-}++-- note applicative composition doesn't give StateT+-- There is a difference between StateT s m and State s (m a)+-- +{-+newtype AccT m a = AccT (Int# -> m (Acc a))++instance Functor f => Applicative (AccT s f) where+    fmap f (AccT m) = AccT (fmap (fmap f) . m)++instance Applicative m => Applicative (AccT s m) where+    pure a = AccT (\i -> return (Acc i a))+    AccT mf <*> AccT ma = AccT (\i -> +        let maccf = mf i +    ++        m (Acc (a -> b)) -> m (Acc a)+-}++{-+traverseBy :: (Traversable t, Applicative f) => (f b -> f b -> Bool) -> (Int -> f b) -> (a -> f b) -> t a -> f (t b)+sequence   :: (Traversable t, Monad m, Eq (m a)) => (Int -> m a) -> t (m a) -> m (t a)+sequenceBy :: (Traversable t, Monad m) => (m a -> m a -> Bool) -> (Int -> m a) -> t (m a) -> m (t a)+sequenceA   :: (Traversable t, Applicative f, Eq (f a)) => (Int -> f a) -> t (f a) -> f (t a)+sequenceByA :: (Traversable t, Applicative f) => (f a -> f a -> Bool) -> (Int -> f a) -> t (f a) -> f (t a)+sequenceSTM   :: (Traversable t, Eq a) => (Int -> STM a) -> t (STM a) -> STM (t a)+sequenceBySTM :: Traversable t => (a -> a -> STM Bool) -> (Int -> STM a) -> t (STM a) -> STM (t a)+mapM :: (Traversable t, Monad m, Eq (m b)) => (Int -> m b) -> (a -> m b) -> t a -> m (t b)+mapByM :: (Traversable t, Monad m) => (m b -> m b -> Bool) -> (Int -> m b) -> (a -> m b) -> t a -> m (t b)+mapSTM :: (Traversable t, Eq b) => (Int -> STM b) -> (a -> STM b) -> t a -> STM (t b)+mapBySTM :: Traversable t => (b -> b -> STM Bool) -> (Int -> STM b) -> (a -> STM b) -> t a -> STM (t b)+mapAccumR :: (Traversable t, Eq a, Eq c) => (Int -> (a, c)) -> (a -> b -> (a, c)) -> a -> t b -> (a, t c)+mapAccumRBy :: Traversable t => ((a, c) -> (a, c) -> Bool) -> (Int -> (a, c)) -> (a -> b -> (a, c)) -> a -> t b -> (a, t c)+mapAccumLBy :: Traversable t => ((a, c) -> (a, c) -> Bool) -> (Int -> (a, c)) -> (a -> b -> (a, c)) -> a -> t b -> (a, t c)+for :: (Traversable t, Applicative f, Eq (f b)) => (Int -> f b) -> t a -> (a -> f b) -> f (t b)+forBy :: (Traversable t, Applicative f) => (f b -> f b -> Bool) -> (Int -> f b) -> t a -> (a -> f b) -> f (t b)+forM :: (Traversable t, Monad m, Eq (m b)) => (Int -> m b) -> t a -> (a -> m b) -> m (t b)+forByM :: (Traversable t, Monad m) => (m b -> m b -> Bool) -> (Int -> m b) -> t a -> (a -> m b) -> m (t b)+forSTM :: (Traversable t, Eq b) => (Int -> STM b) -> t a -> (a -> STM b) -> STM (t b)+forBySTM :: Traversable t => (b -> b -> STM Bool) -> (Int -> STM b) -> t a -> (a -> STM b) -> STM (t b)+-}+
+ ISSUES.markdown view
@@ -0,0 +1,32 @@+sparking the right computation+------------------------------++Currently the computation of 'spec g f a' does exactly what I want+the computation of 'f g' happens in the spark queue through 'par'+while the computation of 'a' happens in the foreground, as well as+any (lazy) evaluation of 'f a'.++(TODO: flop the other of g and a in the cmp to force them in reverse order, to make g even lazier?)++However specSTM lacks this property. the 'par' has to launch the +computation of 'a' because 'f g' is in STM. Can we play games with par  +to retain ownership of the STM transaction and move it into the par block, +and rendezvous with it upon the completion of calculating 'a' ? Per Marlow,+apparently not. This leads to a fallback plan:++sparking only when it makes sense+---------------------------------++Another option (from talking with Simon Marlow) is to add a new primop:++    numSparks# :: State# s -> (# Int#, State# s #)++which computes dequeElements(cap->spark) and to not speculate when that is too high.++Sadly, the cap and spark machinery is marked private by GHC, so this needs to become+a ticket.++unboxed tag-checking+--------------------++For tag checking purposes, we should be able to unsafeCoerce# a :: Word#, but it isn't subkinded. Ticket?
speculation.cabal view
@@ -1,5 +1,5 @@ name:           speculation-version:        0.8.0.2+version:        0.8.1.0 license:        BSD3 license-file:   LICENSE author:         Edward A. Kmett@@ -49,6 +49,7 @@ extra-source-files:      README.markdown     CHANGELOG.markdown+    ISSUES.markdown  source-repository head   type:     git@@ -58,6 +59,7 @@ flag lib   description: Build the library. Useful for speeding up the modify-build-test cycle.   default:     True+  manual:      True  flag tests   description: Build the tests@@ -75,7 +77,6 @@   description: Use HPC for tests   default:     True - library   if !flag(lib)     buildable: False@@ -86,12 +87,17 @@      build-depends:       base >= 4 && < 6,+      ghc-prim >= 0.2 && < 0.3,       parallel >= 2.2 && < 2.3,       stm >= 2.1 && < 2.2      exposed-modules:       Control.Concurrent.Speculation       Data.Foldable.Speculation+      Data.Traversable.Speculation+      Data.List.Speculation+    other-modules:+      Control.Concurrent.Speculation.Internal  executable test-speculation   main-is: Test.hs@@ -104,6 +110,8 @@     ghc-options: -Wall     build-depends:       base >= 4 && < 6, +      ghc-prim >= 0.2 && < 0.3,+      parallel >= 2.2 && < 2.3,       stm >= 2.1 && < 2.2,       containers >= 0.3.0 && < 0.4,       test-framework >= 0.2.4 && < 0.3,@@ -112,8 +120,11 @@       QuickCheck >= 1.2.0.0 && < 1.3,       HUnit >= 1.2.2.1 && < 1.3     other-modules:+      Control.Concurrent.Speculation.Internal       Control.Concurrent.Speculation       Data.Foldable.Speculation+      Data.Traversable.Speculation+      Data.List.Speculation  executable benchmark-speculation   main-is: Benchmark.hs@@ -125,9 +136,14 @@       ghc-options: -O2 -fspec-constr -funbox-strict-fields -fdicts-cheap     build-depends:       base >= 4 && < 6, +      ghc-prim >= 0.2 && < 0.3,+      parallel >= 2.2 && < 2.3,       stm >= 2.1 && < 2.2,       containers >= 0.3.0 && < 0.4,       criterion >= 0.5 && < 0.6     other-modules:+      Control.Concurrent.Speculation.Internal       Control.Concurrent.Speculation       Data.Foldable.Speculation+      Data.Traversable.Speculation+      Data.List.Speculation