foldl-transduce 0.4.3.0 → 0.4.4.0
raw patch · 4 files changed
+140/−38 lines, 4 filesdep +profunctorsdep +tasty-quickcheckdep +voidPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies added: profunctors, tasty-quickcheck, void
API changes (from Hackage documentation)
- Control.Foldl.Transduce: getMoore :: Moore a b u -> Cofree ((->) u) (ReifiedTransduction' a b u)
- Control.Foldl.Transduce: getMooreM :: MooreM m a b u -> Cofree ((->) u) (ReifiedTransductionM' m a b u)
- Control.Foldl.Transduce: getTransduction' :: ReifiedTransduction' a b r -> Transduction' a b r
- Control.Foldl.Transduce: getTransductionM' :: ReifiedTransductionM' m a b r -> TransductionM' m a b r
- Control.Foldl.Transduce: instance (Functor m, Monad m) => Bifunctor (TransducerM m i)
- Control.Foldl.Transduce: instance (m ~ m', Monad m') => ToTransductionsM' m (MooreM m')
- Control.Foldl.Transduce: instance (m ~ m', Monad m') => ToTransductionsM' m (ReifiedTransductionM' m')
- Control.Foldl.Transduce: instance (m ~ m', Monad m') => ToTransductionsM' m (TransducerM m')
- Control.Foldl.Transduce: instance Bifunctor (Transducer i)
- Control.Foldl.Transduce: instance Comonad (Fold a)
- Control.Foldl.Transduce: instance Comonad (Transducer i o)
- Control.Foldl.Transduce: instance Extend (Fold a)
- Control.Foldl.Transduce: instance Extend (Transducer i o)
- Control.Foldl.Transduce: instance Functor (Transducer i o)
- Control.Foldl.Transduce: instance Monad m => Extend (FoldM m a)
- Control.Foldl.Transduce: instance Monad m => Extend (TransducerM m i o)
- Control.Foldl.Transduce: instance Monad m => Functor (TransducerM m i o)
- Control.Foldl.Transduce: instance Monad m => ToFoldM m Fold
- Control.Foldl.Transduce: instance Monad m => ToTransducerM m Transducer
- Control.Foldl.Transduce: instance Monad m => ToTransductionsM' m Transducer
- Control.Foldl.Transduce: instance ToFold (FoldM Identity)
- Control.Foldl.Transduce: instance ToFold Fold
- Control.Foldl.Transduce: instance ToTransducer (TransducerM Identity)
- Control.Foldl.Transduce: instance ToTransducer Transducer
- Control.Foldl.Transduce: instance ToTransductions' Moore
- Control.Foldl.Transduce: instance ToTransductions' ReifiedTransduction'
- Control.Foldl.Transduce: instance ToTransductions' Transducer
- Control.Foldl.Transduce: instance m ~ m' => ToFoldM m (FoldM m')
- Control.Foldl.Transduce: instance m ~ m' => ToTransducerM m (TransducerM m')
+ Control.Foldl.Transduce: Fallible :: FoldM (ExceptT e m) i r -> Fallible m r i e
+ Control.Foldl.Transduce: [getFallible] :: Fallible m r i e -> FoldM (ExceptT e m) i r
+ Control.Foldl.Transduce: [getMooreM] :: MooreM m a b u -> Cofree ((->) u) (ReifiedTransductionM' m a b u)
+ Control.Foldl.Transduce: [getMoore] :: Moore a b u -> Cofree ((->) u) (ReifiedTransduction' a b u)
+ Control.Foldl.Transduce: [getTransduction'] :: ReifiedTransduction' a b r -> Transduction' a b r
+ Control.Foldl.Transduce: [getTransductionM'] :: ReifiedTransductionM' m a b r -> TransductionM' m a b r
+ Control.Foldl.Transduce: instance (GHC.Base.Functor m, GHC.Base.Monad m) => Data.Bifunctor.Bifunctor (Control.Foldl.Transduce.TransducerM m i)
+ Control.Foldl.Transduce: instance (GHC.Base.Functor m, GHC.Base.Monad m) => Data.Profunctor.Unsafe.Profunctor (Control.Foldl.Transduce.Fallible m r)
+ Control.Foldl.Transduce: instance (GHC.Base.Functor m, GHC.Base.Monad m) => GHC.Base.Applicative (Control.Foldl.Transduce.Fallible m r i)
+ Control.Foldl.Transduce: instance (GHC.Base.Functor m, GHC.Base.Monad m) => GHC.Base.Functor (Control.Foldl.Transduce.Fallible m r i)
+ Control.Foldl.Transduce: instance (GHC.Base.Functor m, GHC.Base.Monad m) => GHC.Base.Monad (Control.Foldl.Transduce.Fallible m r i)
+ Control.Foldl.Transduce: instance (GHC.Base.Functor m, GHC.Base.Monad m, GHC.Base.Monoid r) => Data.Profunctor.Choice (Control.Foldl.Transduce.Fallible m r)
+ Control.Foldl.Transduce: instance (m ~ m') => Control.Foldl.Transduce.ToFoldM m (Control.Foldl.FoldM m')
+ Control.Foldl.Transduce: instance (m ~ m') => Control.Foldl.Transduce.ToTransducerM m (Control.Foldl.Transduce.TransducerM m')
+ Control.Foldl.Transduce: instance (m ~ m', GHC.Base.Monad m') => Control.Foldl.Transduce.ToTransductionsM' m (Control.Foldl.Transduce.MooreM m')
+ Control.Foldl.Transduce: instance (m ~ m', GHC.Base.Monad m') => Control.Foldl.Transduce.ToTransductionsM' m (Control.Foldl.Transduce.ReifiedTransductionM' m')
+ Control.Foldl.Transduce: instance (m ~ m', GHC.Base.Monad m') => Control.Foldl.Transduce.ToTransductionsM' m (Control.Foldl.Transduce.TransducerM m')
+ Control.Foldl.Transduce: instance Control.Comonad.Comonad (Control.Foldl.Transduce.Transducer i o)
+ Control.Foldl.Transduce: instance Control.Foldl.Transduce.ToFold (Control.Foldl.FoldM Data.Functor.Identity.Identity)
+ Control.Foldl.Transduce: instance Control.Foldl.Transduce.ToFold Control.Foldl.Fold
+ Control.Foldl.Transduce: instance Control.Foldl.Transduce.ToTransducer (Control.Foldl.Transduce.TransducerM Data.Functor.Identity.Identity)
+ Control.Foldl.Transduce: instance Control.Foldl.Transduce.ToTransducer Control.Foldl.Transduce.Transducer
+ Control.Foldl.Transduce: instance Control.Foldl.Transduce.ToTransductions' Control.Foldl.Transduce.Moore
+ Control.Foldl.Transduce: instance Control.Foldl.Transduce.ToTransductions' Control.Foldl.Transduce.ReifiedTransduction'
+ Control.Foldl.Transduce: instance Control.Foldl.Transduce.ToTransductions' Control.Foldl.Transduce.Transducer
+ Control.Foldl.Transduce: instance Data.Bifunctor.Bifunctor (Control.Foldl.Transduce.Transducer i)
+ Control.Foldl.Transduce: instance Data.Functor.Extend.Extend (Control.Foldl.Fold a)
+ Control.Foldl.Transduce: instance Data.Functor.Extend.Extend (Control.Foldl.Transduce.Transducer i o)
+ Control.Foldl.Transduce: instance GHC.Base.Functor (Control.Foldl.Transduce.Transducer i o)
+ Control.Foldl.Transduce: instance GHC.Base.Monad m => Control.Foldl.Transduce.ToFoldM m Control.Foldl.Fold
+ Control.Foldl.Transduce: instance GHC.Base.Monad m => Control.Foldl.Transduce.ToTransducerM m Control.Foldl.Transduce.Transducer
+ Control.Foldl.Transduce: instance GHC.Base.Monad m => Control.Foldl.Transduce.ToTransductionsM' m Control.Foldl.Transduce.Transducer
+ Control.Foldl.Transduce: instance GHC.Base.Monad m => Data.Functor.Extend.Extend (Control.Foldl.FoldM m a)
+ Control.Foldl.Transduce: instance GHC.Base.Monad m => Data.Functor.Extend.Extend (Control.Foldl.Transduce.TransducerM m i o)
+ Control.Foldl.Transduce: instance GHC.Base.Monad m => GHC.Base.Functor (Control.Foldl.Transduce.TransducerM m i o)
+ Control.Foldl.Transduce: newtype Fallible m r i e
- Control.Foldl.Transduce: transduceK :: Monad m => (i -> m [o]) -> TransductionM m i o
+ Control.Foldl.Transduce: transduceK :: (Monad m) => (i -> m [o]) -> TransductionM m i o
- Control.Foldl.Transduce.ByteString.IO: toHandle :: MonadIO m => Handle -> FoldM m ByteString ()
+ Control.Foldl.Transduce.ByteString.IO: toHandle :: (MonadIO m) => Handle -> FoldM m ByteString ()
- Control.Foldl.Transduce.ByteString.IO: toHandleBuilder :: MonadIO m => Handle -> FoldM m Builder ()
+ Control.Foldl.Transduce.ByteString.IO: toHandleBuilder :: (MonadIO m) => Handle -> FoldM m Builder ()
Files
- CHANGELOG +6/−0
- foldl-transduce.cabal +4/−1
- src/Control/Foldl/Transduce.hs +104/−36
- tests/tests.hs +26/−1
CHANGELOG view
@@ -1,4 +1,10 @@+# 0.4.4.0++- deprecated quiesceWith+- added Fallible.+ # 0.4.3.0+ - deprecated splitWhen in favor of break - deprecated textualSplitWhen in favor of textualBreak
foldl-transduce.cabal view
@@ -1,5 +1,5 @@ Name: foldl-transduce-Version: 0.4.3.0+Version: 0.4.4.0 Cabal-Version: >=1.8.0.2 Build-Type: Simple License: BSD3@@ -29,10 +29,12 @@ transformers >= 0.2.0.0 && < 0.5 , containers < 0.6 , bifunctors == 5.* ,+ profunctors == 5.* , semigroupoids >= 5.0 , foldl >= 1.1 && < 2 , comonad == 4.* , free == 4.* , + void >= 0.6 , monoid-subclasses == 0.4.* Exposed-Modules: Control.Foldl.Transduce,@@ -63,6 +65,7 @@ text , tasty >= 0.10.1.1 , tasty-hunit >= 0.9.2,+ tasty-quickcheck >= 0.8.3.2, monoid-subclasses == 0.4.*, foldl , foldl-transduce
src/Control/Foldl/Transduce.hs view
@@ -6,11 +6,20 @@ {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE CPP #-} --- |------ This module builds on module "Control.Foldl", adding stateful transducers--- and grouping operations.+{-| This module builds on module "Control.Foldl", adding stateful transducers+ and grouping operations. +>>> L.fold (transduce (surround "[" "]") L.list) "middle"+"[middle]"++>>> L.fold (folds (chunksOf 2) L.length L.list) "aabbccdd"+[2,2,2,2]++>>> L.fold (groups (chunksOf 2) (surround "[" "]") L.list) "aabbccdd"+"[aa][bb][cc][dd]"++-}+ module Control.Foldl.Transduce ( -- * Transducer types Transduction @@ -71,11 +80,11 @@ , condenseM , hoistTransducer -- * Fold utilities- , quiesce- , quiesceWith , hoistFold , unit , trip+ , quiesce+ , Fallible(..) , ToFold(..) , ToFoldM(..) -- * Re-exports@@ -85,12 +94,16 @@ , module Control.Comonad.Cofree -- * Deprecated , splitWhen+ , quiesceWith ) where import Prelude hiding (splitAt,break) +import Data.Functor import Data.Bifunctor+import Data.Profunctor import Data.Monoid+import Data.Void import qualified Data.Monoid.Cancellative as CM import qualified Data.Monoid.Null as NM import qualified Data.Monoid.Factorial as SFM@@ -101,6 +114,7 @@ import Control.Applicative import Control.Monad import Control.Monad.IO.Class+import Control.Monad.Trans.Class import Control.Monad.Trans.Except import Control.Comonad import Control.Comonad.Cofree @@ -312,6 +326,7 @@ instance Monad m => ToFoldM m Fold where toFoldM = L.generalize + {-| Apply a 'Transducer' to a 'Fold', discarding the return value of the 'Transducer'. @@ -538,42 +553,95 @@ Left e -> return (Left e) Right r -> return (Right r) -{-| Generalized version of 'quiesce' to turn a fallible 'FoldM' into another- that starts a "fallback fold" when it encounters an error.+--{-| Generalized version of 'quiesce' to turn a fallible 'FoldM' into another+-- that starts a "fallback fold" when it encounters an error.+--+-- "Start folding this way, if you encounter an error, start folding this +-- other way". +--+-- >>> L.foldM (quiesceWith (L.generalize L.length) (FoldM (\_ _-> throwE ()) (return ()) (\_ -> throwE ()))) [1..7]+-- Left ((),7)+---}+{-# DEPRECATED quiesceWith "The signature of this function will change." #-}+quiesceWith :: (Functor m,Monad m) => FoldM m a v -> FoldM (ExceptT e m) a r -> FoldM m a (Either (e,v) r)+quiesceWith fallback original = hoistFold (fmap (either absurd id) . runExceptT) (getFallible (do+ e <- Fallible (fmap Right original)+ Fallible (hoistFold lift (fmap (\x -> Left (e,x)) fallback)))) - "Start folding this way, if you encounter an error, start folding this - other way". +newtype Fallible m r i e = Fallible { getFallible :: FoldM (ExceptT e m) i r } ->>> L.foldM (quiesceWith (L.generalize L.length) (FoldM (\_ _-> throwE ()) (return ()) (\_ -> throwE ()))) [1..7]-Left ((),7)--}-quiesceWith :: (Functor m,Monad m) => FoldM m a v -> FoldM (ExceptT e m) a r -> FoldM m a (Either (e,v) r)-quiesceWith fallbackFold (FoldM step initial done) = - FoldM step' (runExceptT (withExceptT (Pair fallbackFold) initial)) done'- where- step' x i = do - case x of- Left (Pair ffold e) -> do- ffold' <- L.foldM (duplicated ffold) [i]- return (Left (Pair ffold' e))+bindFallible :: (Functor m,Monad m) => Fallible m r i e -> (e -> Fallible m r i e') -> Fallible m r i e'+bindFallible (Fallible (FoldM step initial done)) k =+ Fallible (FoldM step' (lift (runExceptT (withExceptT (getFallible . k) initial))) done')+ where + step' x i = ExceptT (case x of+ Left ffold -> do+ rx <- runExceptT (L.foldM (duplicated ffold) [i])+ case rx of+ Left e' -> return (Left e') -- true failure+ Right ffold' -> return (Right (Left ffold')) Right notyetfail -> do x' <- runExceptT (step notyetfail i) case x' of Left e -> do- ffold <- L.foldM (duplicated fallbackFold) [i]- return (Left (Pair ffold e))- Right x'' -> return (Right x'')- done' x = case x of- Left (Pair ffold e) -> do- alternativeResult <- L.foldM ffold []- return (Left (e,alternativeResult))- Right notyetfail -> do - x' <- runExceptT (done notyetfail)- case x' of- Left e -> do- alternativeResult <- L.foldM fallbackFold []- return (Left (e,alternativeResult))- Right x'' -> return (Right x'')+ return (Right (Left ((getFallible . k) e)))+ Right x'' -> return (Right (Right x'')))+ done' x = ExceptT (case x of+ Left ffold -> do+ rx <- runExceptT (L.foldM ffold [])+ case rx of+ Left e' -> return (Left e') -- true failure+ Right r -> return (Right r)+ Right notyetfail -> do+ x' <- runExceptT (done notyetfail)+ case x' of+ Left e -> do+ runExceptT (done' (Left (getFallible (k e))))+ Right x'' -> return (Right x''))++instance (Functor m, Monad m) => Functor (Fallible m r i) where+ fmap g (Fallible fallible) = + Fallible (hoistFold (withExceptT g) fallible)+++{-| 'pure' creates a 'Fallible' that starts in a failed state. ++-}+instance (Functor m,Monad m) => Applicative (Fallible m r i) where+ pure e = Fallible (FoldM (\_ _ -> throwE e) (throwE e) (\_ -> throwE e))++ u <*> v = u >>= \f -> fmap f v++instance (Functor m, Monad m) => Profunctor (Fallible m r) where+ lmap f (Fallible fallible) = + Fallible (L.premapM f fallible)++ rmap g (Fallible fallible) = + Fallible (hoistFold (withExceptT g) fallible)++{-| Fail immediately when an input comes in the wrong branch. ++-}+instance (Functor m,Monad m,Monoid r) => Choice (Fallible m r) where+ left' (Fallible fallible) = + Fallible (liftA2 mappend (hoistFold (withExceptT Left) (L.handlesM _Left fallible)) (hoistFold (withExceptT Right) (L.handlesM _Right (trip $> mempty))))++_Left :: Applicative f => (a -> f a) -> Either a b -> f (Either a b)+_Left f e = case e of+ Right b -> pure (Right b)+ Left a -> fmap Left (f a)++_Right :: Applicative f => (b -> f b) -> Either a b -> f (Either a b)+_Right f e = case e of+ Left b -> pure (Left b)+ Right a -> fmap Right (f a)++{-| '>>=' continues folding after an error using a 'Fallible' constructed from the error. ++-}+instance (Functor m,Monad m) => Monad (Fallible m r i) where+ (>>=) = bindFallible+ return = pure {-| The "do-nothing" fold.
tests/tests.hs view
@@ -1,14 +1,16 @@ module Main where -import Prelude hiding (splitAt)+import Prelude hiding (splitAt,lines,words) import Data.String hiding (lines,words) import Data.Monoid import Data.Bifunctor import qualified Data.Monoid.Factorial as SFM import Test.Tasty import Test.Tasty.HUnit+import Test.Tasty.QuickCheck import qualified Data.Text as T+import qualified Data.Text.Lazy as TL import qualified Control.Foldl as L import Control.Foldl.Transduce@@ -18,6 +20,15 @@ main :: IO () main = defaultMain tests +newtype WordQC = WordQC { getWordQC :: T.Text } deriving (Show)++instance Arbitrary WordQC where+ arbitrary = do+ firstChar <- oneof [pure ' ', pure '\n', arbitrary]+ lastChar <- oneof [pure ' ', pure '\n', arbitrary]+ middle <- listOf (frequency [(1,pure ' '),(4,arbitrary)])+ return (WordQC (T.pack (firstChar : (middle ++ [lastChar]))))+ tests :: TestTree tests = testGroup "Tests" @@ -72,6 +83,20 @@ assertEqual mempty (T.pack "\n") (mconcat (L.fold (transduce newline L.list) (map T.pack [""])))+ ]+ ,+ testGroup "words" + [ + testGroup "quickcheck" + [ + testProperty "quickcheck1" (\chunks -> + let tchunks = fmap getWordQC chunks + in+ (case TL.words (TL.fromChunks tchunks) of+ [] -> [mempty]+ x -> x) ==+ (fmap TL.fromChunks (L.fold (folds words L.list L.list) tchunks)))+ ] ] , testGroup "quiesceWith" $