streaming-eversion 0.1.0.0 → 0.2.0.0
raw patch · 6 files changed
+176/−142 lines, 6 filesdep +errorsdep +microlensdep +pipes-bytestringdep ~pipes
Dependencies added: errors, microlens, pipes-bytestring
Dependency ranges changed: pipes
Files
- CHANGELOG +8/−0
- README.md +2/−2
- src/Streaming/Eversion.hs +93/−69
- src/Streaming/Eversion/Pipes.hs +54/−54
- streaming-eversion.cabal +11/−9
- tests/tests.hs +8/−8
CHANGELOG view
@@ -0,0 +1,8 @@+0.2.0.0+=======++- Eversible, not Evertible!+- Removed special purpose error functions.+- Added some utility functions.+- Added Category instances.+
README.md view
@@ -24,13 +24,13 @@ more natural. The pipes ecosystem already provides a lot of them: [parsers](http://hackage.haskell.org/package/pipes-parse), [decoders](http://hackage.haskell.org/package/pipes-text),-[splitters](http://hackage.haskell.org/package/pipes-group)...+[splitters](http://hackage.haskell.org/package/pipes-group). However, push-based mode also has advantages. Push-based abstractions are not tied to a particular type of source because data is fed externally. And foldl folds have very useful Applicative and Comonad instances. -Also, sometimes, a library will only offer a push-based interface. +Also, sometimes a library will only offer a push-based interface. Wouldn't it be nice if you could adapt already existing pull-based operations to work on push-based consumers? For example, using a decoding function from
src/Streaming/Eversion.hs view
@@ -1,55 +1,62 @@ {-# LANGUAGE RankNTypes #-} -{-| The pull-to-push transformations in this module require functions that are +{-| Most pull-to-push transformations in this module require functions that are polymorphic over a monad transformer. Because of this, some of the type signatures look scary, but actually many (suitably polymorphic) operations on 'Stream's will unify with them. To get "interruptible" operations that can exit early with an error, put a- 'ExceptT' transformer just below the polymorphic monad transformer. See- 'foldE'.+ 'ExceptT' transformer just below the polymorphic monad transformer. In+ practice, that means lifting functions like+ 'Control.Monad.Trans.ExceptT.throwE' and 'Control.Error.Util.hoistEither' a+ number of times. Inspired by http://pchiusano.blogspot.com.es/2011/12/programmatic-translation-to-iteratees.html -} module Streaming.Eversion (- -- * Evertible Stream folds- Evertible- , evertible+ -- * Stream folds + Eversible+ , eversible , evert- , EvertibleM- , evertibleM+ , EversibleM+ , eversibleM+ , eversibleM_ , evertM- , EvertibleMIO- , evertibleMIO+ , EversibleMIO+ , eversibleMIO+ , eversibleMIO_ , evertMIO- -- * Transvertible Stream transformations+ -- * Stream transformations , Transvertible , transvertible , transvert , TransvertibleM , transvertibleM+ , runTransvertibleM , transvertM , TransvertibleMIO , transvertibleMIO+ , runTransvertibleMIO , transvertMIO- -- * Auxiliary functions- , foldE ) where +import Prelude hiding ((.),id) import Data.Bifunctor import Data.Profunctor +import Control.Category import Control.Foldl (Fold(..),FoldM(..)) import qualified Control.Foldl as Foldl-import Streaming (Stream,Of(..))+import Streaming (Stream,Of(..),hoist,distribute) import Streaming.Prelude (yield,next) import qualified Streaming.Prelude as S import Control.Monad.IO.Class import Control.Monad.Trans.Class+import Control.Monad.Trans.Identity import Control.Monad.Free import qualified Control.Monad.Trans.Free as TF import Control.Monad.Trans.Except@@ -62,7 +69,7 @@ >>> import Control.Foldl (Fold(..),FoldM(..)) >>> import qualified Control.Foldl as L >>> import Streaming (Stream,Of(..))->>> import Streaming.Prelude (yield,next)+>>> import Streaming.Prelude (yield,next,for) >>> import qualified Streaming.Prelude as S -} @@ -95,15 +102,15 @@ ----------------------------------------------------------------------------------------- --- | A stream-consuming function that can be turned into a pure, push-based fold. -newtype Evertible a x = - Evertible (forall m r. Monad m => Stream (Of a) m r -> m (Of x r)) +-- | A stream-folding function that can be turned into a pure, push-based fold. +newtype Eversible a x = + Eversible (forall m r. Monad m => Stream (Of a) m r -> m (Of x r)) -instance Functor (Evertible a) where- fmap f (Evertible somefold) = Evertible (fmap (first f) . somefold) +instance Functor (Eversible a) where+ fmap f (Eversible somefold) = Eversible (fmap (first f) . somefold) -instance Profunctor Evertible where- lmap f (Evertible somefold) = Evertible (somefold . S.map f)+instance Profunctor Eversible where+ lmap f (Eversible somefold) = Eversible (somefold . S.map f) rmap = fmap stoppedBeforeEOF :: String@@ -112,11 +119,12 @@ continuedAfterEOF :: String continuedAfterEOF = "Continued after receiving EOF." -evertible :: (forall m r. Monad m => Stream (Of a) m r -> m (Of x r)) -> Evertible a x-evertible = Evertible+eversible :: (forall m r. Monad m => Stream (Of a) m r -> m (Of x r)) -> Eversible a x+eversible = Eversible -evert :: Evertible a x -> Fold a x-evert (Evertible consumer) = Fold step begin done++evert :: Eversible a x -> Fold a x+evert (Eversible consumer) = Fold step begin done where begin = consumer evertedStream step s a = case s of@@ -129,32 +137,36 @@ Free _ -> error continuedAfterEOF -{- | Like 'Evertible', but gives the stream-consuming function access to a base monad.+{- | Like 'Eversible', but gives the stream-folding function access to a base monad. >>> :{- let f stream = fmap ((:>) ()) (lift (putStrLn "x") >> S.effects stream)- in L.foldM (evertM (evertibleM f)) ["a","b","c"]+ let consume stream = lift (putStrLn "x") >> S.effects stream+ in L.foldM (evertM (eversibleM_ consume)) ["a","b","c"] :} x Note however that control operations can't be lifted through the transformer. -}-newtype EvertibleM m a x = - EvertibleM (forall t r. (MonadTrans t, Monad (t m)) => Stream (Of a) (t m) r -> t m (Of x r)) +newtype EversibleM m a x = + EversibleM (forall t r. (MonadTrans t, Monad (t m)) => Stream (Of a) (t m) r -> t m (Of x r)) -instance Functor (EvertibleM m a) where- fmap f (EvertibleM somefold) = EvertibleM (fmap (first f) . somefold) +instance Functor (EversibleM m a) where+ fmap f (EversibleM somefold) = EversibleM (fmap (first f) . somefold) -instance Profunctor (EvertibleM m) where- lmap f (EvertibleM somefold) = EvertibleM (somefold . S.map f)+instance Profunctor (EversibleM m) where+ lmap f (EversibleM somefold) = EversibleM (somefold . S.map f) rmap = fmap -evertibleM ::(forall t r . (MonadTrans t, Monad (t m)) => Stream (Of a) (t m) r -> t m (Of x r)) -- ^- -> EvertibleM m a x-evertibleM = EvertibleM +eversibleM ::(forall t r . (MonadTrans t, Monad (t m)) => Stream (Of a) (t m) r -> t m (Of x r)) -- ^+ -> EversibleM m a x+eversibleM = EversibleM -evertM :: Monad m => EvertibleM m a x -> FoldM m a x-evertM (EvertibleM consumer) = FoldM step begin done+eversibleM_ :: (forall t r . (MonadTrans t, Monad (t m)) => Stream (Of a) (t m) r -> t m r) -- ^+ -> EversibleM m a ()+eversibleM_ f = EversibleM (fmap (fmap ((:>) ())) f)++evertM :: Monad m => EversibleM m a x -> FoldM m a x+evertM (EversibleM consumer) = FoldM step begin done where begin = return (consumer evertedStreamM) step (TF.FreeT ms) i = do@@ -173,30 +185,34 @@ TF.Pure (a :> ()) -> return a TF.Free _ -> error continuedAfterEOF -{-| Like 'EvertibleM', but gives the stream-consuming function the ability to use 'liftIO'.+{-| Like 'EversibleM', but gives the stream-consuming function the ability to use 'liftIO'. ->>> L.foldM (evertMIO (evertibleMIO (\stream -> fmap ((:>) ()) (S.print stream)))) ["a","b","c"]+>>> L.foldM (evertMIO (eversibleMIO_ S.print)) ["a","b","c"] "a" "b" "c" -}-newtype EvertibleMIO m a x = - EvertibleMIO (forall t r. (MonadTrans t, MonadIO (t m)) => Stream (Of a) (t m) r -> t m (Of x r)) +newtype EversibleMIO m a x = + EversibleMIO (forall t r. (MonadTrans t, MonadIO (t m)) => Stream (Of a) (t m) r -> t m (Of x r)) -instance Functor (EvertibleMIO m a) where- fmap f (EvertibleMIO somefold) = EvertibleMIO (fmap (first f) . somefold) +instance Functor (EversibleMIO m a) where+ fmap f (EversibleMIO somefold) = EversibleMIO (fmap (first f) . somefold) -instance Profunctor (EvertibleMIO m) where- lmap f (EvertibleMIO somefold) = EvertibleMIO (somefold . S.map f)+instance Profunctor (EversibleMIO m) where+ lmap f (EversibleMIO somefold) = EversibleMIO (somefold . S.map f) rmap = fmap -evertibleMIO ::(forall t r . (MonadTrans t, MonadIO (t m)) => Stream (Of a) (t m) r -> t m (Of x r)) -- ^- -> EvertibleMIO m a x-evertibleMIO = EvertibleMIO +eversibleMIO ::(forall t r . (MonadTrans t, MonadIO (t m)) => Stream (Of a) (t m) r -> t m (Of x r)) -- ^+ -> EversibleMIO m a x+eversibleMIO = EversibleMIO -evertMIO :: MonadIO m => EvertibleMIO m a x -> FoldM m a x -evertMIO (EvertibleMIO consumer) = FoldM step begin done+eversibleMIO_ :: (forall t r . (MonadTrans t, MonadIO (t m)) => Stream (Of a) (t m) r -> t m r) -- ^+ -> EversibleMIO m a ()+eversibleMIO_ f = EversibleMIO (fmap (fmap ((:>) ())) f)++evertMIO :: MonadIO m => EversibleMIO m a x -> FoldM m a x +evertMIO (EversibleMIO consumer) = FoldM step begin done where begin = return (consumer evertedStreamM) step (TF.FreeT ms) i = do@@ -226,6 +242,10 @@ lmap f (Transvertible somefold) = Transvertible (somefold . S.map f) rmap = fmap +instance Category Transvertible where+ id = Transvertible id+ (.) = \(Transvertible t1) (Transvertible t2) -> Transvertible (t1 . t2)+ data Pair a b = Pair !a !b data StreamState a b = Pristine (Stream (Of b) (Iteratee (Feed a)) ())@@ -278,6 +298,16 @@ -> TransvertibleM m a b transvertibleM = TransvertibleM +instance Category (TransvertibleM m) where+ id = TransvertibleM id+ (.) = \(TransvertibleM t1) (TransvertibleM t2) -> TransvertibleM (t1 . t2)++-- | Recover the stored function, discarding the transformer.+-- +runTransvertibleM :: TransvertibleM m a b -- ^+ -> (forall r. Monad m => Stream (Of a) m r -> Stream (Of b) m r) +runTransvertibleM (TransvertibleM t) = \stream -> runIdentityT (distribute (t (hoist lift stream)))+ instance Functor (TransvertibleM m a) where fmap f (TransvertibleM transducer) = TransvertibleM (S.map f . transducer) @@ -333,11 +363,15 @@ TF.Free _ -> error continuedAfterEOF --- | Like 'TransvertibleM', but gives the stream-consuming function the ability to use 'liftIO'.+-- | Like 'TransvertibleM', but gives the stream-transforming function the ability to use 'liftIO'. -- newtype TransvertibleMIO m a b = TransvertibleMIO (forall t r. (MonadTrans t, MonadIO (t m)) => Stream (Of a) (t m) r -> Stream (Of b) (t m) r) +instance Category (TransvertibleMIO m) where+ id = TransvertibleMIO id+ (.) = \(TransvertibleMIO t1) (TransvertibleMIO t2) -> TransvertibleMIO (t1 . t2)+ instance Functor (TransvertibleMIO m a) where fmap f (TransvertibleMIO transducer) = TransvertibleMIO (S.map f . transducer) @@ -349,8 +383,12 @@ -> TransvertibleMIO m a b transvertibleMIO = TransvertibleMIO +runTransvertibleMIO :: TransvertibleMIO m a b -- ^+ -> (forall r. MonadIO m => Stream (Of a) m r -> Stream (Of b) m r) +runTransvertibleMIO (TransvertibleMIO t) = \stream -> runIdentityT (distribute (t (hoist lift stream)))+ transvertMIO :: (MonadIO m) - => TransvertibleMIO m b a + => TransvertibleMIO m b a -- ^ -> (forall x . FoldM m a x -> FoldM m b x) transvertMIO (TransvertibleMIO transducer) somefold = FoldM step begin done@@ -396,18 +434,4 @@ advancefinal step1 future TF.Pure (Left ()) -> return innerfold TF.Free _ -> error continuedAfterEOF--{-| If your stream-folding computation can fail early returning a 'Left',- compose it with this function before passing it to 'evertibleM'. -- The result will be an 'EvertibleM' that works on 'ExceptT'.-->>> runExceptT $ L.foldM (evertM (evertibleM (foldE . (\_ -> return (Left ()))))) [1..10]-Left ()---} -foldE :: (MonadTrans t, Monad m, Monad (t (ExceptT e m))) - => t (ExceptT e m) (Either e r) -- ^- -> t (ExceptT e m) r-foldE action = action >>= lift . ExceptT . return
src/Streaming/Eversion/Pipes.hs view
@@ -4,28 +4,28 @@ -- module Streaming.Eversion.Pipes (- -- * Evertible Producer folds- pipeEvertible+ -- * Producer folds + pipeEversible , evert- , pipeEvertibleM+ , pipeEversibleM+ , pipeEversibleM_ , evertM- , pipeEvertibleMIO+ , pipeEversibleMIO+ , pipeEversibleMIO_ , evertMIO- -- * Transvertible Producer transformations+ -- * Producer transformations , pipeTransvertible , transvert , pipeTransvertibleM , transvertM , pipeTransvertibleMIO , transvertMIO- -- * Auxiliary functions- , pipeLeftoversE- , pipeTransE+ -- * Examples+ -- $examples ) where import Control.Monad.IO.Class import Control.Monad.Trans.Class-import Control.Monad.Trans.Except import Streaming(Of(..)) import qualified Streaming.Prelude@@ -36,6 +36,10 @@ {- $setup >>> :set -XOverloadedStrings >>> import Data.Functor.Identity+>>> import Data.Bifunctor+>>> import Data.Bitraversable+>>> import Control.Error+>>> import Control.Monad >>> import Control.Monad.Trans.Except >>> import Control.Monad.Trans.Identity >>> import Control.Foldl (Fold(..),FoldM(..))@@ -45,25 +49,35 @@ >>> import qualified Streaming.Prelude as S >>> import Pipes >>> import qualified Pipes.Prelude as P->>> import qualified Pipes.Text as T->>> import qualified Pipes.Text.Encoding as TE+>>> import qualified Pipes.Text as PT+>>> import qualified Pipes.Text.Encoding as PT+>>> import qualified Pipes.ByteString as PB+>>> import Lens.Micro.Extras -} ----------------------------------------------------------------------------------------- -pipeEvertible :: (forall m r. Monad m => Producer a m r -> m (x,r)) -- ^- -> Evertible a x-pipeEvertible f = evertible (\stream -> fmap (\(x,r) -> x :> r) (f (Pipes.Prelude.unfoldr Streaming.Prelude.next stream)))+pipeEversible :: (forall m r. Monad m => Producer a m r -> m (x,r)) -- ^+ -> Eversible a x+pipeEversible f = eversible (\stream -> fmap (\(x,r) -> x :> r) (f (Pipes.Prelude.unfoldr Streaming.Prelude.next stream))) -pipeEvertibleM :: (forall t r. (MonadTrans t, Monad (t m)) => Producer a (t m) r -> t m (x,r)) -- ^- -> EvertibleM m a x-pipeEvertibleM f = evertibleM (\stream -> fmap (\(x,r) -> x :> r) (f (Pipes.Prelude.unfoldr Streaming.Prelude.next stream)))+pipeEversibleM :: (forall t r. (MonadTrans t, Monad (t m)) => Producer a (t m) r -> t m (x,r)) -- ^+ -> EversibleM m a x+pipeEversibleM f = eversibleM (\stream -> fmap (\(x,r) -> x :> r) (f (Pipes.Prelude.unfoldr Streaming.Prelude.next stream))) -pipeEvertibleMIO :: (forall t r. (MonadTrans t, MonadIO (t m)) => Producer a (t m) r -> t m (x,r)) -- ^- -> EvertibleMIO m a x-pipeEvertibleMIO f = evertibleMIO (\stream -> fmap (\(x,r) -> x :> r) (f (Pipes.Prelude.unfoldr Streaming.Prelude.next stream)))+pipeEversibleM_ :: (forall t r. (MonadTrans t, Monad (t m)) => Producer a (t m) r -> t m r) -- ^+ -> EversibleM m a ()+pipeEversibleM_ f = eversibleM (\stream -> fmap (\r -> () :> r) (f (Pipes.Prelude.unfoldr Streaming.Prelude.next stream))) +pipeEversibleMIO :: (forall t r. (MonadTrans t, MonadIO (t m)) => Producer a (t m) r -> t m (x,r)) -- ^+ -> EversibleMIO m a x+pipeEversibleMIO f = eversibleMIO (\stream -> fmap (\(x,r) -> x :> r) (f (Pipes.Prelude.unfoldr Streaming.Prelude.next stream)))++pipeEversibleMIO_ :: (forall t r. (MonadTrans t, MonadIO (t m)) => Producer a (t m) r -> t m r) -- ^+ -> EversibleMIO m a ()+pipeEversibleMIO_ f = eversibleMIO (\stream -> fmap (\r -> () :> r) (f (Pipes.Prelude.unfoldr Streaming.Prelude.next stream)))+ pipeTransvertible :: (forall m r. Monad m => Producer a m r -> Producer b m r) -- ^ -> Transvertible a b pipeTransvertible pt = transvertible (\stream -> Streaming.Prelude.unfoldr Pipes.next (pt (Pipes.Prelude.unfoldr Streaming.Prelude.next stream)))@@ -72,52 +86,38 @@ -> TransvertibleM m a b pipeTransvertibleM pt = transvertibleM (\stream -> Streaming.Prelude.unfoldr Pipes.next (pt (Pipes.Prelude.unfoldr Streaming.Prelude.next stream))) --- -- | Ignore the somewhat baroque type and just remember that you can plug any of the "non-lens decoding functions" from "Pipes.Text.Encoding" here.--- ----- -- The result is a 'TransvertibleM' that works in 'ExceptT'. If any undecodable bytes are found, the computation halts with the undecodable bytes as the error.--- pipeDecoderTransvertibleE :: Monad m => (forall t r .(MonadTrans t, Monad (t (ExceptT bytes m))) => (Producer bytes (t (ExceptT bytes m)) r -> Producer text (t (ExceptT bytes m)) (Producer bytes (t (ExceptT bytes m)) r))) -- ^--- -> TransvertibleM (ExceptT bytes m) bytes text--- pipeDecoderTransvertibleE decoder = pipeTransvertibleM (pipeLeftoversE . decoder) pipeTransvertibleMIO :: (forall t r. (MonadTrans t, MonadIO (t m)) => Producer a (t m) r -> Producer b (t m) r) -- ^ -> TransvertibleMIO m a b pipeTransvertibleMIO pt = transvertibleMIO (\stream -> Streaming.Prelude.unfoldr Pipes.next (pt (Pipes.Prelude.unfoldr Streaming.Prelude.next stream))) -{-| Allows you to plug any of the "non-lens decoding functions" from "Pipes.Text.Encoding" into 'pipeTransvertibleM'. Just - compose the decoder with this function before passing it to 'pipeTransvertibleM'.-- The result will be a 'TransvertibleM' that works in 'ExceptT'. +{- $examples+ + Creating a 'TransvertibleM' out a decoder from "Pipes.Text.Encoding". In+ case the decoding fails, part of the leftovers are read in order to build+ the error value. >>> :{ - let adapted = transvertM (pipeTransvertibleM (pipeLeftoversE . TE.decodeUtf8)) (L.generalize L.mconcat) - in runExceptT $ L.foldM adapted ["decode","this"]+ let trans = transvertM (pipeTransvertibleM (\producer -> do result <- PT.decode (PT.utf8 . PT.eof) producer + lift (case result of+ Left ls -> sample ls >>= lift . throwE+ Right r -> return r)))+ sample leftovers = L.purely P.fold L.mconcat (void (view (PB.splitAt 5) leftovers))+ in runExceptT $ L.foldM (trans (L.generalize L.mconcat)) ["decode","this"] :} Right "decodethis" - If any undecodable bytes are found, the computation halts with the undecoded bytes as the error.- >>> :{ - let adapted = transvertM (pipeTransvertibleM (pipeLeftoversE . TE.decodeUtf8)) (L.generalize L.mconcat) - in runExceptT $ L.foldM adapted ["invalid \xc3\x28","sequence"]+ let trans = transvertM (pipeTransvertibleM (\producer -> do result <- PT.decode (PT.utf8 . PT.eof) producer + lift (case result of+ Left ls -> sample ls >>= lift . throwE+ Right r -> return r)))+ sample leftovers = L.purely P.fold L.mconcat (void (view (PB.splitAt 8) leftovers))+ in runExceptT $ L.foldM (trans (L.generalize L.mconcat)) ["invalid \xc3\x28","sequence"] :}-Left "\195("---}-pipeLeftoversE :: (MonadTrans t, Monad m, Monad (t (ExceptT bytes m))) => Producer text (t (ExceptT bytes m)) (Producer bytes (t (ExceptT bytes m)) r) -- ^- -> Producer text (t (ExceptT bytes m)) r-pipeLeftoversE decodedProducer = decodedProducer >>= \leftoversProducer -> do- leftovers <- lift (next leftoversProducer)- case leftovers of - Left r -> return r- Right (firstleftover,_) -> lift (lift (throwE firstleftover))+Left "\195(sequen" -{-| If your producer-transforming computation can fail early returning a 'Left',- compose it with this function before passing it to 'transvertibleM'. +Note that the errors are thrown in an 'ExceptT' layer below the 'Pipes.Producer'+and the polymorphic transformer. - The result will be an 'TransvertibleM' that works on 'ExceptT'. -}-pipeTransE :: (MonadTrans t, Monad m, Monad (t (ExceptT e m))) - => Producer a (t (ExceptT e m)) (Either e r) -- ^- -> Producer a (t (ExceptT e m)) r-pipeTransE producer = producer >>= lift . lift . ExceptT . return-
streaming-eversion.cabal view
@@ -1,5 +1,5 @@ Name: streaming-eversion-Version: 0.1.0.0+Version: 0.2.0.0 Cabal-Version: >=1.8.0.2 Build-Type: Simple License: BSD3@@ -31,7 +31,7 @@ profunctors >= 5 , free >= 4 , foldl >= 1.1.5 ,- pipes >= 4.2.0 ,+ pipes >= 4.1.0 , streaming >= 0.1.4.2 Exposed-Modules: Streaming.Eversion@@ -44,13 +44,15 @@ hs-source-dirs: tests main-is: doctests.hs build-depends:- base >= 4.4 && < 5 ,- doctest >= 0.10.1 ,- foldl >= 1.1.5 ,- pipes >= 4.1.9 ,- pipes-text >= 0.0.2.2 ,- streaming >= 0.1.4.2 -+ base >= 4.4 && < 5 ,+ doctest >= 0.10.1 ,+ foldl >= 1.1.5 ,+ pipes >= 4.1.0 ,+ pipes-text >= 0.0.2.2 ,+ pipes-bytestring >= 2.1.1 ,+ streaming >= 0.1.4.2 , + microlens >= 0.4.2.1 ,+ errors >= 2.1.0 test-suite tests type: exitcode-stdio-1.0 ghc-options: -Wall -threaded
tests/tests.hs view
@@ -22,27 +22,27 @@ testCaseEq "empty" ([]::[Integer])- (Foldl.fold (evert (evertible S.toList)) [])+ (Foldl.fold (evert (eversible S.toList)) []) , testCaseEq "toList" [1..10::Integer]- (Foldl.fold (evert (evertible S.toList)) [1..10])+ (Foldl.fold (evert (eversible S.toList)) [1..10]) ] , testGroup "evertM" [ testCaseEq "empty" ([]::[Integer])- (runIdentity (Foldl.foldM (evertM (evertibleM S.toList)) []))+ (runIdentity (Foldl.foldM (evertM (eversibleM S.toList)) [])) , testCaseEq "toList" [1..10::Integer]- (runIdentity (Foldl.foldM (evertM (evertibleM S.toList)) [1..10]))+ (runIdentity (Foldl.foldM (evertM (eversibleM S.toList)) [1..10])) , testCaseEqIO "ref" (True,[1..10::Integer]) (do ref <- newIORef False - res <- Foldl.foldM (evertM (evertibleM (\s -> S.toList s <* lift (writeIORef ref True)))) [1..10]+ res <- Foldl.foldM (evertM (eversibleM (\s -> S.toList s <* lift (writeIORef ref True)))) [1..10] refval <- readIORef ref return (refval,res)) ]@@ -51,16 +51,16 @@ testCaseEqIO "empty" ([]::[Integer])- (Foldl.foldM (evertMIO (evertibleMIO S.toList)) [])+ (Foldl.foldM (evertMIO (eversibleMIO S.toList)) []) , testCaseEqIO "toList" [1..10::Integer]- (Foldl.foldM (evertMIO (evertibleMIO S.toList)) [1..10])+ (Foldl.foldM (evertMIO (eversibleMIO S.toList)) [1..10]) , testCaseEqIO "ref" (True,[1..10::Integer]) (do ref <- newIORef False - res <- Foldl.foldM (evertMIO (evertibleMIO (\s -> S.toList s <* liftIO (writeIORef ref True)))) [1..10]+ res <- Foldl.foldM (evertMIO (eversibleMIO (\s -> S.toList s <* liftIO (writeIORef ref True)))) [1..10] refval <- readIORef ref return (refval,res)) ]