constrictor 0.1.1.0 → 0.1.1.1
raw patch · 2 files changed
+121/−52 lines, 2 filesdep +ghc-primdep ~basePVP: minor bump suggested
API additions: PVP suggests at least a minor version bump
Dependencies added: ghc-prim
Dependency ranges changed: base
API changes (from Hackage documentation)
+ Constrictor: traverse'' :: (Traversable t, Monad m) => (a -> m b) -> t a -> m (t b)
Files
- constrictor.cabal +3/−2
- src/Constrictor.hs +118/−50
constrictor.cabal view
@@ -1,7 +1,7 @@ name: constrictor version:- 0.1.1.0+ 0.1.1.1 synopsis: strict versions of many things in base description:@@ -34,7 +34,8 @@ exposed-modules: Constrictor build-depends:- base >=4.7 && < 5.0+ base >=4.5 && < 5.0+ , ghc-prim , transformers default-language: Haskell2010
src/Constrictor.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE CPP #-}+{-# LANGUAGE BangPatterns #-} {-# LANGUAGE DeriveFoldable #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE DeriveGeneric #-}@@ -11,11 +12,16 @@ functions in base, as well as a few functions that do not have lazy versions that exist in base (see the section on Folds).++Many functions in this library have an increased+constraint from Functor/Applicative to Monad in+order to achieve strictness in their arguments+and/or result. -} module Constrictor ( - -- * Strict monadic functions + -- * Strict 'lift-like' functions (<$!>) , fmap' , liftM'@@ -24,9 +30,8 @@ , liftM4' , liftM5' , ap' - - -- * Strict traversable functions , traverse'+ , traverse'' , mapM' -- * Folds@@ -47,31 +52,51 @@ , Ap(..) ) where +import Prelude hiding (foldr,foldl)+ import Control.Applicative import Control.Monad (MonadPlus)+#if MIN_VERSION_base(4,9,0) import Control.Monad.Fail (MonadFail)+#endif import Control.Monad.Fix (MonadFix)-import Control.Monad.Trans.Cont (evalCont, cont)+import Control.Monad.Trans.Cont (ContT(..), cont) import Data.Foldable import Data.Functor.Compose (Compose(..))+import Data.Functor.Identity (runIdentity) import Data.Monoid hiding ((<>))+#if MIN_VERSION_base(4,9,0) import Data.Semigroup-import Data.Traversable (traverse)+#endif+import Data.Traversable (traverse,Traversable) import GHC.Generics (Generic,Generic1) +#if !(MIN_VERSION_base(4,8,0))+import Control.Applicative (WrappedMonad(..))+#endif+ -- | A wrapped applicative functor. -- Please note that base 4.12.0.0 will include this type, -- and it will be removed from this library at that point. newtype Ap f a = Ap { getAp :: f a } deriving ( Alternative, Applicative , Enum, Eq, Foldable, Functor- , Generic, Generic1- , Monad, MonadFail, MonadFix, MonadPlus+ , Generic+#if MIN_VERSION_base(4,6,0)+ , Generic1+#endif+ , Monad+#if MIN_VERSION_base(4,9,0)+ , MonadFail+#endif+ , MonadFix, MonadPlus , Num, Ord, Read, Show, Traversable ) +#if MIN_VERSION_base(4,9,0) instance (Applicative f, Semigroup a) => Semigroup (Ap f a) where (Ap x) <> (Ap y) = Ap $ liftA2 (<>) x y+#endif instance (Applicative f, Monoid a) => Monoid (Ap f a) where mempty = Ap $ pure mempty@@ -82,57 +107,81 @@ -- | Lazy in the monoidal accumulator. Monoidal accumulation -- happens from left to right. foldlMapA :: forall t b a f. (Foldable t, Monoid b, Applicative f) => (a -> f b) -> t a -> f b-foldlMapA f = foldr f' (pure mempty)- where- f' :: a -> f b -> f b- f' x y = liftA2 mappend (f x) y+foldlMapA f = foldr (\x y -> liftA2 mappend (f x) y) (pure mempty) -- | Lazy in the monoidal accumulator. Monoidal accumulation -- happens from left to right. foldrMapA :: forall t b a f. (Foldable t, Monoid b, Applicative f) => (a -> f b) -> t a -> f b-foldrMapA f = foldl f' (pure mempty)- where- f' :: f b -> a -> f b- f' y x = liftA2 (flip mappend) (f x) y+foldrMapA f = foldl (\y x -> liftA2 (flip mappend) (f x) y) (pure mempty) -- | Strict in the monoidal accumulator. -- For monads strict in the left argument of bind, -- this will run in constant space. -- Monoidal accumulation happens from left to right. foldlMapM' :: forall t b a m. (Foldable t, Monoid b, Monad m) => (a -> m b) -> t a -> m b-foldlMapM' f xs = foldr f' pure xs mempty+foldlMapM' f xs = foldr f' return xs mempty where f' :: a -> (b -> m b) -> b -> m b f' x k bl = do- br <- f x+ !br <- f x k $! (mappend bl br) -- Strict in the monoidal accumulator. -- Monoidal accumulation happens from left to right. foldrMapM' :: forall t b a m. (Foldable t, Monoid b, Monad m) => (a -> m b) -> t a -> m b-foldrMapM' f xs = foldl f' pure xs mempty+foldrMapM' f xs = foldl f' return xs mempty where f' :: (b -> m b) -> a -> b -> m b f' k x br = do- bl <- f x+ !bl <- f x k $! (mappend bl br) infixl 4 <$!>, `fmap'`, `liftM'` --- | Strict version of 'Data.Functor.<$>'+-- | This is 'Data.Functor.<$>', but strict in its+-- argument and result.+--+-- This is re-defined in this module, and not+-- just re-exported from @'Control.Monad'@.+-- The reason for this is that there is no way+-- to hide the docs for re-exports with Haddocks.+--+-- In the common case that one might import+-- @'Control.Monad'@, we recommend structuring+-- imports like so:+--+-- @+-- import Control.Monad hiding ((<$!>))+-- import Constrictor+-- @+--+-- or+--+-- @+-- import Control.Monad+-- import Constrictor hiding ((<$!>))+-- @+--+-- There should be no side effects (i.e.+-- naming/scoping conflicts) introduced as a+-- result of structuring one's imports in this way. (<$!>) :: Monad m => (a -> b) -> m a -> m b {-# INLINE (<$!>) #-} f <$!> m = do- x <- m- pure $! f x+ !x <- m+ return $! f x +-- | This is 'Data.Functor.fmap', but strict in its+-- argument and result.+-- -- Note this is equivalent to '<$!>', -- and is provided for convenience. fmap' :: Monad m => (a -> b) -> m a -> m b {-# INLINE fmap' #-} fmap' = (<$!>) --- | Strict version of 'Control.Monad.liftM'.+-- | This is 'Control.Monad.liftM', but strict in its+-- argument and result. -- -- Note this is equivalent to '<$!>', -- and is provided for convenience.@@ -140,63 +189,82 @@ {-# INLINE liftM' #-} liftM' = (<$!>) --- | Strict version of 'Control.Monad.liftM2'.+-- | This is 'Control.Monad.liftM2', but strict in its+-- arguments and result. liftM2' :: Monad m => (a -> b -> c) -> m a -> m b -> m c {-# INLINE liftM2' #-} liftM2' f a b = do- x <- a- y <- b- pure $! f x y+ !x <- a+ !y <- b+ return $! f x y --- | Strict version of 'Control.Monad.liftM3'.+-- | This is 'Control.Monad.liftM3', but strict in its+-- arguments and result. liftM3' :: Monad m => (a -> b -> c -> d) -> m a -> m b -> m c -> m d {-# INLINE liftM3' #-} liftM3' f a b c = do- x <- a- y <- b- z <- c- pure $! f x y z+ !x <- a+ !y <- b+ !z <- c+ return $! f x y z --- | Strict version of 'Control.Monad.liftM4'.+-- | This is 'Control.Monad.liftM4', but strict in its+-- arguments and result. liftM4' :: Monad m => (a -> b -> c -> d -> e) -> m a -> m b -> m c -> m d -> m e {-# INLINE liftM4' #-} liftM4' f a b c d = do- x <- a- y <- b- z <- c- u <- d- pure $! f x y z u+ !x <- a+ !y <- b+ !z <- c+ !u <- d+ return $! f x y z u --- | Strict version of 'Control.Monad.liftM5'.+-- | This is 'Control.Monad.liftM5', but strict in its+-- arguments and result. liftM5' :: Monad m => (a -> b -> c -> d -> e -> f) -> m a -> m b -> m c -> m d -> m e -> m f {-# INLINE liftM5' #-} liftM5' f a b c d e = do- x <- a- y <- b- z <- c- u <- d- v <- e- pure $! f x y z u v+ !x <- a+ !y <- b+ !z <- c+ !u <- d+ !v <- e+ return $! f x y z u v --- | Strict version of 'Control.Monad.ap'+-- | This is 'Control.Monad.ap', but strict in its+-- arguments and result. ap' :: Monad m => m (a -> b) -> m a -> m b {-# INLINE ap' #-} ap' m1 m2 = do- f <- m1- x <- m2- pure $! f x+ !f <- m1+ !x <- m2+ return $! f x -- | Strict version of 'Data.Traversable.traverse'. traverse' :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b) {-# INLINE traverse' #-}-traverse' f = fmap evalCont . getCompose . traverse (Compose . fmap (\a -> cont $ \k -> k $! a) . f)+traverse' f = fmap (runIdentity . evalContT) . getCompose . traverse (Compose . fmap (\a -> cont $ \k -> k $! a) . f) +-- | Stricter version of 'Data.Traversable.traverse'.+traverse'' :: (Traversable t, Monad m) => (a -> m b) -> t a -> m (t b)+{-# INLINE traverse'' #-}+traverse'' f = fmap' (runIdentity . evalContT) . getCompose . traverse (Compose . fmap' (\a -> cont $ \k -> k $! a) . f)++-- this is copied from transformers for backwards compatibility+evalContT :: (Monad m) => ContT r m r -> m r+evalContT m = runContT m return+{-# INLINE evalContT #-}+ -- | Strict version of 'Control.Monad.mapM'. -- -- This is just 'traverse'' specialised to 'Monad'. mapM' :: (Traversable t, Monad m) => (a -> m b) -> t a-> m (t b) {-# INLINE mapM' #-}+#if MIN_VERSION_base(4,8,0) mapM' = traverse'+#else+mapM' f xs = unwrapMonad (traverse' (\x -> WrapMonad (f x)) xs)+#endif -- The INLINES used below allow more list functions to fuse. -- See Trac #9848.