list-t 0.2.7 → 0.3.0
raw patch · 4 files changed
+170/−172 lines, 4 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- ListT: class MonadPlus m => ListMonad m
- ListT: class MonadTrans t => ListTrans t
- ListT: instance ListMonad []
- ListT: instance ListMonad m => ListMonad (ReaderT e m)
- ListT: instance ListTrans ListT
- ListT: instance Monad m => ListMonad (ListT m)
+ ListT: class MonadPlus m => MonadCons m
+ ListT: class MonadTrans t => MonadTransUncons t
+ ListT: instance Monad m => MonadCons (ListT m)
+ ListT: instance MonadCons []
+ ListT: instance MonadCons m => MonadCons (ReaderT e m)
+ ListT: instance MonadTransUncons ListT
- ListT: cons :: ListMonad m => a -> m a -> m a
+ ListT: cons :: MonadCons m => a -> m a -> m a
- ListT: fold :: (Monad m, ListTrans t) => (r -> a -> m r) -> r -> t m a -> m r
+ ListT: fold :: (Monad m, MonadTransUncons t) => (r -> a -> m r) -> r -> t m a -> m r
- ListT: fromFoldable :: (ListMonad m, Foldable f) => f a -> m a
+ ListT: fromFoldable :: (MonadCons m, Foldable f) => f a -> m a
- ListT: head :: (Monad m, ListTrans t) => t m a -> m (Maybe a)
+ ListT: head :: (Monad m, MonadTransUncons t) => t m a -> m (Maybe a)
- ListT: null :: (Monad m, ListTrans t) => t m a -> m Bool
+ ListT: null :: (Monad m, MonadTransUncons t) => t m a -> m Bool
- ListT: repeat :: ListMonad m => a -> m a
+ ListT: repeat :: MonadCons m => a -> m a
- ListT: splitAt :: (Monad m, ListTrans t, MonadPlus (t m)) => Int -> t m a -> m ([a], t m a)
+ ListT: splitAt :: (Monad m, MonadTransUncons t, MonadPlus (t m)) => Int -> t m a -> m ([a], t m a)
- ListT: tail :: (Monad m, ListTrans t) => t m a -> m (Maybe (t m a))
+ ListT: tail :: (Monad m, MonadTransUncons t) => t m a -> m (Maybe (t m a))
- ListT: toList :: (Monad m, ListTrans t) => t m a -> m [a]
+ ListT: toList :: (Monad m, MonadTransUncons t) => t m a -> m [a]
- ListT: toReverseList :: (Monad m, ListTrans t) => t m a -> m [a]
+ ListT: toReverseList :: (Monad m, MonadTransUncons t) => t m a -> m [a]
- ListT: traverse_ :: (Monad m, ListTrans t) => (a -> m ()) -> t m a -> m ()
+ ListT: traverse_ :: (Monad m, MonadTransUncons t) => (a -> m ()) -> t m a -> m ()
- ListT: type Transformation m a b = forall t. (Monad m, ListMonad (t m), ListTrans t) => t m a -> t m b
+ ListT: type Transformation m a b = forall t. (Monad m, MonadCons (t m), MonadTransUncons t) => t m a -> t m b
- ListT: uncons :: ListTrans t => t m a -> m (Maybe (a, t m a))
+ ListT: uncons :: (MonadTransUncons t, Monad m) => t m a -> m (Maybe (a, t m a))
- ListT: unfold :: ListMonad m => (b -> Maybe (a, b)) -> b -> m a
+ ListT: unfold :: MonadCons m => (b -> Maybe (a, b)) -> b -> m a
Files
- executables/APITests.hs +0/−137
- library/ListT.hs +29/−31
- list-t.cabal +4/−4
- tests/Main.hs +137/−0
− executables/APITests.hs
@@ -1,137 +0,0 @@-{-# OPTIONS_GHC -F -pgmF htfpp #-}--import BasePrelude hiding (toList)-import MTLPrelude-import Test.Framework-import qualified ListT as L---main = htfMain $ htf_thisModulesTests----- * Applicative----------------------------prop_applicativeIdentityLaw (l :: [Int]) =- runIdentity $ streamsEqual (pure id <*> s) s- where- s = L.fromFoldable l--prop_applicativeBehavesLikeList =- \(ns :: [Int]) ->- let a = fs <*> ns- b = runIdentity (toList $ L.fromFoldable fs <*> L.fromFoldable ns)- in a == b- where- fs = [(+1), (+3), (+5)]----- * Monad----------------------------test_monadLaw1 =- assertBool =<< streamsEqual (return a >>= k) (k a)- where- a = 2- k a = return $ chr a--test_monadLaw2 =- assertBool =<< streamsEqual (m >>= return) m- where- m = L.fromFoldable ['a'..'z']--test_monadLaw3 =- assertBool =<< streamsEqual (m >>= (\x -> k x >>= h)) ((m >>= k) >>= h)- where- m = L.fromFoldable ['a'..'z']- k a = return $ ord a- h a = return $ a + 1--test_monadLaw4 =- assertBool =<< streamsEqual (fmap f xs) (xs >>= return . f)- where- f = ord- xs = L.fromFoldable ['a'..'z']----- * Monoid----------------------------test_mappend =- assertBool =<< - streamsEqual - (L.fromFoldable [0..7]) - (L.fromFoldable [0..3] <> L.fromFoldable [4..7])--test_mappendAndTake =- assertBool =<< - streamsEqual - (L.fromFoldable [0..5]) - (L.take 6 $ L.fromFoldable [0..3] <> L.fromFoldable [4..7])--test_mappendDoesntCauseTraversal =- do- ref <- newIORef 0- (flip runReaderT) ref (toList $ L.take 5 $ stream <> stream)- assertEqual 5 =<< readIORef ref- where- stream =- do- ref <- lift $ ask- x <- L.fromFoldable [0..4]- liftIO $ modifyIORef ref (+1)- return x----- * Other----------------------------test_repeat =- assertEqual [2,2,2] =<< do- toList $ L.take 3 $ L.repeat (2 :: Int)--test_traverseDoesntCauseTraversal =- do- ref <- newIORef 0- (flip runReaderT) ref (toList stream3)- assertEqual 3 =<< readIORef ref- where- stream1 =- do- ref <- lift $ ask- x <- L.fromFoldable ['a'..'z']- liftIO $ modifyIORef ref (+1)- return x- stream2 =- L.traverse (return . toUpper) stream1- stream3 =- L.take 3 stream2--test_takeDoesntCauseTraversal =- do- ref <- newIORef 0- (flip runReaderT) ref (toList $ L.take 3 $ L.take 7 $ stream)- assertEqual 3 =<< readIORef ref- where- stream =- do- ref <- lift $ ask- x <- L.fromFoldable [0..10]- liftIO $ modifyIORef ref (+1)- return x--test_drop =- assertEqual [3, 4] =<< do- toList $ L.drop 2 $ L.fromFoldable [1 .. 4]- -test_slice =- assertEqual ["abc", "def", "gh"] =<< do- toList $ L.slice (fromJust $ L.positive 3) $ L.fromFoldable ("abcdefgh" :: [Char])---toList :: Monad m => L.ListT m a -> m [a]-toList = L.toList--streamsEqual :: (Applicative m, Monad m, Eq a) => L.ListT m a -> L.ListT m a -> m Bool-streamsEqual a b =- (==) <$> L.toList a <*> L.toList b
library/ListT.hs view
@@ -3,8 +3,8 @@ ( ListT, -- * Classes- ListTrans(..),- ListMonad(..),+ MonadTransUncons(..),+ MonadCons(..), -- * Execution utilities head, tail,@@ -35,7 +35,7 @@ ) where -import BasePrelude hiding (uncons, toList, yield, fold, traverse, head, tail, take, drop, repeat, null, traverse_, splitAt)+import BasePrelude hiding (toList, yield, fold, traverse, head, tail, take, drop, repeat, null, traverse_, splitAt) import Control.Monad.Morph hiding (MonadTrans(..)) import Control.Monad.IO.Class import Control.Monad.Trans.Class@@ -44,7 +44,7 @@ import Control.Monad.Base -- |--- A proper implementation of a list monad-transformer.+-- A proper implementation of the list monad-transformer. -- Useful for streaming of monadic data structures. -- -- Since it has instances of 'MonadPlus' and 'Alternative',@@ -133,34 +133,34 @@ ------------------------- -- |--- A monad transformer capable of executing like a list.-class MonadTrans t => ListTrans t where+-- A monad transformer capable of deconstructing like a list.+class MonadTrans t => MonadTransUncons t where -- | -- Execute in the inner monad, -- getting the head and the tail. -- Returns nothing if it's empty.- uncons :: t m a -> m (Maybe (a, t m a))+ uncons :: Monad m => t m a -> m (Maybe (a, t m a)) -instance ListTrans ListT where+instance MonadTransUncons ListT where {-# INLINE uncons #-} uncons (ListT m) = m -- | -- A monad capable of constructing like a list.-class MonadPlus m => ListMonad m where+class MonadPlus m => MonadCons m where -- | -- Prepend an element. cons :: a -> m a -> m a -instance ListMonad [] where+instance MonadCons [] where cons a m = a : m -instance Monad m => ListMonad (ListT m) where+instance Monad m => MonadCons (ListT m) where {-# INLINABLE cons #-} cons h t = ListT $ return (Just (h, t)) -instance ListMonad m => ListMonad (ReaderT e m) where+instance MonadCons m => MonadCons (ReaderT e m) where cons a m = ReaderT $ cons a . runReaderT m @@ -170,35 +170,35 @@ -- | -- Execute, getting the head. Returns nothing if it's empty. {-# INLINABLE head #-}-head :: (Monad m, ListTrans t) => t m a -> m (Maybe a)+head :: (Monad m, MonadTransUncons t) => t m a -> m (Maybe a) head = liftM (fmap fst) . uncons -- | -- Execute, getting the tail. Returns nothing if it's empty. {-# INLINABLE tail #-}-tail :: (Monad m, ListTrans t) => t m a -> m (Maybe (t m a))+tail :: (Monad m, MonadTransUncons t) => t m a -> m (Maybe (t m a)) tail = liftM (fmap snd) . uncons -- | -- Execute, checking whether it's empty. {-# INLINABLE null #-}-null :: (Monad m, ListTrans t) => t m a -> m Bool+null :: (Monad m, MonadTransUncons t) => t m a -> m Bool null = liftM (maybe True (const False)) . uncons -- | -- Execute, applying a left fold. {-# INLINABLE fold #-}-fold :: (Monad m, ListTrans t) => (r -> a -> m r) -> r -> t m a -> m r+fold :: (Monad m, MonadTransUncons t) => (r -> a -> m r) -> r -> t m a -> m r fold s r = uncons >=> maybe (return r) (\(h, t) -> s r h >>= \r' -> fold s r' t) -- | -- Execute, folding to a list. {-# INLINABLE toList #-}-toList :: (Monad m, ListTrans t) => t m a -> m [a]+toList :: (Monad m, MonadTransUncons t) => t m a -> m [a] toList = liftM ($ []) . fold (\f e -> return $ f . (e :)) id @@ -206,21 +206,21 @@ -- Execute, folding to a list in a reverse order. -- Performs more efficiently than 'toList'. {-# INLINABLE toReverseList #-}-toReverseList :: (Monad m, ListTrans t) => t m a -> m [a]+toReverseList :: (Monad m, MonadTransUncons t) => t m a -> m [a] toReverseList = ListT.fold (\l -> return . (:l)) [] -- | -- Execute, traversing the stream with a side effect in the inner monad. {-# INLINABLE traverse_ #-}-traverse_ :: (Monad m, ListTrans t) => (a -> m ()) -> t m a -> m ()+traverse_ :: (Monad m, MonadTransUncons t) => (a -> m ()) -> t m a -> m () traverse_ f = fold (const f) () -- | -- Execute, consuming a list of the specified length and returning the remainder stream. {-# INLINABLE splitAt #-}-splitAt :: (Monad m, ListTrans t, MonadPlus (t m)) => Int -> t m a -> m ([a], t m a)+splitAt :: (Monad m, MonadTransUncons t, MonadPlus (t m)) => Int -> t m a -> m ([a], t m a) splitAt = \case n | n > 0 -> \l ->@@ -239,21 +239,21 @@ -- | -- Construct from any foldable. {-# INLINABLE fromFoldable #-}-fromFoldable :: (ListMonad m, Foldable f) => f a -> m a+fromFoldable :: (MonadCons m, Foldable f) => f a -> m a fromFoldable = foldr cons mzero -- | -- Construct by unfolding a pure data structure. {-# INLINABLE unfold #-}-unfold :: (ListMonad m) => (b -> Maybe (a, b)) -> b -> m a+unfold :: (MonadCons m) => (b -> Maybe (a, b)) -> b -> m a unfold f s = maybe mzero (\(h, t) -> cons h (unfold f t)) (f s) -- | -- Produce an infinite stream. {-# INLINABLE repeat #-}-repeat :: (ListMonad m) => a -> m a+repeat :: (MonadCons m) => a -> m a repeat = fix . cons @@ -262,18 +262,16 @@ ------------------------- -- |--- A transformation function on a list transformer.--- It may update the structure or the result type, --- but the type of the transformer remains the same.+-- A function, which updates the contents of a list transformer. -- -- Since it's merely just a function, -- you can run it by passing a list transformer as an argument. type Transformation m a b = - forall t. (Monad m, ListMonad (t m), ListTrans t) =>+ forall t. (Monad m, MonadCons (t m), MonadTransUncons t) => t m a -> t m b -- |--- Produce a transformation,+-- A transformation, -- which traverses the stream with an action in the inner monad. {-# INLINABLE traverse #-} traverse :: (a -> m b) -> Transformation m a b@@ -283,7 +281,7 @@ maybe mzero return -- |--- Produce a transformation,+-- A transformation, -- reproducing the behaviour of @Data.List.'Data.List.take'@. {-# INLINABLE take #-} take :: Int -> Transformation m a a@@ -298,7 +296,7 @@ const $ mzero -- |--- Produce a transformation,+-- A transformation, -- reproducing the behaviour of @Data.List.'Data.List.drop'@. {-# INLINABLE drop #-} drop :: Int -> Transformation m a a@@ -310,7 +308,7 @@ id -- |--- Produce a transformation,+-- A transformation, -- which slices a list into chunks of the specified length. {-# INLINABLE slice #-} slice :: Positive Int -> Transformation m a [a]
list-t.cabal view
@@ -1,7 +1,7 @@ name: list-t version:- 0.2.7+ 0.3.0 synopsis: ListT done right description:@@ -54,13 +54,13 @@ Haskell2010 -test-suite api-tests+test-suite tests type: exitcode-stdio-1.0 hs-source-dirs:- executables+ tests main-is:- APITests.hs+ Main.hs build-depends: list-t, HTF == 0.12.*,
+ tests/Main.hs view
@@ -0,0 +1,137 @@+{-# OPTIONS_GHC -F -pgmF htfpp #-}++import BasePrelude hiding (toList)+import MTLPrelude+import Test.Framework+import qualified ListT as L+++main = htfMain $ htf_thisModulesTests+++-- * Applicative+-------------------------++prop_applicativeIdentityLaw (l :: [Int]) =+ runIdentity $ streamsEqual (pure id <*> s) s+ where+ s = L.fromFoldable l++prop_applicativeBehavesLikeList =+ \(ns :: [Int]) ->+ let a = fs <*> ns+ b = runIdentity (toList $ L.fromFoldable fs <*> L.fromFoldable ns)+ in a == b+ where+ fs = [(+1), (+3), (+5)]+++-- * Monad+-------------------------++test_monadLaw1 =+ assertBool =<< streamsEqual (return a >>= k) (k a)+ where+ a = 2+ k a = return $ chr a++test_monadLaw2 =+ assertBool =<< streamsEqual (m >>= return) m+ where+ m = L.fromFoldable ['a'..'z']++test_monadLaw3 =+ assertBool =<< streamsEqual (m >>= (\x -> k x >>= h)) ((m >>= k) >>= h)+ where+ m = L.fromFoldable ['a'..'z']+ k a = return $ ord a+ h a = return $ a + 1++test_monadLaw4 =+ assertBool =<< streamsEqual (fmap f xs) (xs >>= return . f)+ where+ f = ord+ xs = L.fromFoldable ['a'..'z']+++-- * Monoid+-------------------------++test_mappend =+ assertBool =<< + streamsEqual + (L.fromFoldable [0..7]) + (L.fromFoldable [0..3] <> L.fromFoldable [4..7])++test_mappendAndTake =+ assertBool =<< + streamsEqual + (L.fromFoldable [0..5]) + (L.take 6 $ L.fromFoldable [0..3] <> L.fromFoldable [4..7])++test_mappendDoesntCauseTraversal =+ do+ ref <- newIORef 0+ (flip runReaderT) ref (toList $ L.take 5 $ stream <> stream)+ assertEqual 5 =<< readIORef ref+ where+ stream =+ do+ ref <- lift $ ask+ x <- L.fromFoldable [0..4]+ liftIO $ modifyIORef ref (+1)+ return x+++-- * Other+-------------------------++test_repeat =+ assertEqual [2,2,2] =<< do+ toList $ L.take 3 $ L.repeat (2 :: Int)++test_traverseDoesntCauseTraversal =+ do+ ref <- newIORef 0+ (flip runReaderT) ref (toList stream3)+ assertEqual 3 =<< readIORef ref+ where+ stream1 =+ do+ ref <- lift $ ask+ x <- L.fromFoldable ['a'..'z']+ liftIO $ modifyIORef ref (+1)+ return x+ stream2 =+ L.traverse (return . toUpper) stream1+ stream3 =+ L.take 3 stream2++test_takeDoesntCauseTraversal =+ do+ ref <- newIORef 0+ (flip runReaderT) ref (toList $ L.take 3 $ L.take 7 $ stream)+ assertEqual 3 =<< readIORef ref+ where+ stream =+ do+ ref <- lift $ ask+ x <- L.fromFoldable [0..10]+ liftIO $ modifyIORef ref (+1)+ return x++test_drop =+ assertEqual [3, 4] =<< do+ toList $ L.drop 2 $ L.fromFoldable [1 .. 4]+ +test_slice =+ assertEqual ["abc", "def", "gh"] =<< do+ toList $ L.slice (fromJust $ L.positive 3) $ L.fromFoldable ("abcdefgh" :: [Char])+++toList :: Monad m => L.ListT m a -> m [a]+toList = L.toList++streamsEqual :: (Applicative m, Monad m, Eq a) => L.ListT m a -> L.ListT m a -> m Bool+streamsEqual a b =+ (==) <$> L.toList a <*> L.toList b