packages feed

hierarchy 0.2.1 → 0.3.0

raw patch · 5 files changed

+89/−106 lines, 5 filesdep −unixdep ~directoryPVP ok

version bump matches the API change (PVP)

Dependencies removed: unix

Dependency ranges changed: directory

API changes (from Hackage documentation)

- Control.Cond: applyCondT :: Monad m => a -> CondT a m r -> m (Maybe a, Maybe (CondT a m r))
- Pipes.Tree: directoryFiles :: MonadIO m => FilePath -> TreeT m FilePath
+ Control.Cond: evalCondT :: Monad m => a -> CondT a m r -> m (Maybe r)
+ Control.Cond: execCondT :: Monad m => a -> CondT a m r -> m (Maybe a, Maybe (CondT a m r))
+ Control.Cond: updates :: MonadQuery a m => (a -> a) -> m ()
- Control.Cond: runCond :: Cond a r -> a -> Maybe r
+ Control.Cond: runCond :: a -> Cond a r -> Maybe r
- Control.Cond: runCondT :: Monad m => CondT a m r -> a -> m (Maybe r)
+ Control.Cond: runCondT :: Monad m => a -> CondT a m r -> m ((Maybe r, Maybe (CondT a m r)), a)

Files

Control/Cond.hs view
@@ -17,7 +17,7 @@     ( CondT, Cond      -- * Executing CondT-    , runCondT, runCond, applyCondT+    , runCondT, runCond, execCondT, evalCondT, test      -- * Promotions     , MonadQuery(..), guardM, guard_, guardM_, apply, consider@@ -29,12 +29,12 @@     , matches, if_, when_, unless_, or_, and_, not_      -- * helper functions-    , recurse, test+    , recurse     )     where  import           Control.Applicative-import           Control.Arrow ((***))+import           Control.Arrow (second) import           Control.Monad hiding (mapM_, sequence_) import           Control.Monad.Base import           Control.Monad.Catch@@ -55,7 +55,7 @@ import qualified Control.Monad.Trans.RWS.Lazy as LazyRWS import qualified Control.Monad.Trans.RWS.Strict as StrictRWS import           Control.Monad.Trans.Reader (ReaderT(..))-import           Control.Monad.Trans.State (StateT(..), evalStateT)+import           Control.Monad.Trans.State (StateT(..)) import qualified Control.Monad.Trans.State.Lazy as Lazy import qualified Control.Monad.Trans.State.Strict as Strict import qualified Control.Monad.Trans.Writer.Lazy as Lazy@@ -64,7 +64,6 @@ import           Control.Monad.Zip import           Data.Foldable import           Data.Functor.Identity-import           Data.Maybe (isJust) import           Data.Monoid hiding ((<>)) import           Data.Semigroup import           Prelude hiding (mapM_, foldr1, sequence_)@@ -182,6 +181,8 @@             (v, Continue) -> return (v, Recurse (n >>= k))             x@_ -> return x     {-# INLINEABLE (>>=) #-}+    {-# SPECIALIZE (>>=)+          :: CondT e IO a -> (a -> CondT e IO b) -> CondT e IO b #-}  instance MonadReader r m => MonadReader r (CondT a m) where     ask = lift R.ask@@ -218,6 +219,7 @@             x@(Just _, _) -> return x             _ -> g     {-# INLINEABLE (<|>) #-}+    {-# SPECIALIZE (<|>) :: CondT a IO a -> CondT a IO a -> CondT a IO a #-}  instance Monad m => MonadPlus (CondT a m) where     mzero = CondT $ return recurse'@@ -228,6 +230,7 @@             x@(Just _, _) -> return x             _ -> g     {-# INLINEABLE mplus #-}+    {-# SPECIALIZE mplus :: CondT a IO a -> CondT a IO a -> CondT a IO a #-}  instance MonadError e m => MonadError e (CondT a m) where     throwError = CondT . throwError@@ -252,7 +255,6 @@       where q u = CondT . u . getCondT     {-# INLINEABLE uninterruptibleMask #-} - instance MonadBase b m => MonadBase b (CondT a m) where     liftBase m = CondT $ liftM accept' $ liftBase m     {-# INLINE liftBase #-}@@ -311,33 +313,59 @@             Just b  -> runStateT (getCondT (f b)) a         return ((mb, n), a') -runCondT :: Monad m => CondT a m r -> a -> m (Maybe r)-runCondT (CondT f) a = fst `liftM` evalStateT f a-{-# INLINE runCondT #-}--runCond :: Cond a r -> a -> Maybe r-runCond = (runIdentity .) . runCondT-{-# INLINE runCond #-}- -- | Apply a condition to an input value, returning a (possibly) updated copy -- of that value if it matches, and the next 'CondT' to use if recursion into -- that value was indicated.-applyCondT :: Monad m => a -> CondT a m r -> m (Maybe a, Maybe (CondT a m r))-applyCondT a c@(CondT (StateT s)) = go `liftM` s a+runCondT :: Monad m => a -> CondT a m r -> m ((Maybe r, Maybe (CondT a m r)), a)+runCondT a c@(CondT (StateT s)) = go `liftM` s a   where-    go (p, a') = (fmap (const a') *** recursorToMaybe c) p+    go (p, a') = (second (recursorToMaybe c) p, a')      recursorToMaybe _ Stop        = Nothing     recursorToMaybe p Continue    = Just p     recursorToMaybe _ (Recurse n) = Just n-{-# INLINEABLE applyCondT #-}+{-# INLINEABLE runCondT #-}+{-# SPECIALIZE runCondT+      :: a -> CondT a IO r -> IO ((Maybe r, Maybe (CondT a IO r)), a) #-} +runCond :: a -> Cond a r -> Maybe r+runCond = ((fst . fst . runIdentity) .) . runCondT+{-# INLINE runCond #-}++execCondT :: Monad m => a -> CondT a m r -> m (Maybe a, Maybe (CondT a m r))+execCondT a c = go `liftM` runCondT a c+  where+    go ((mr, mnext), a') = (const a' <$> mr, mnext)+{-# INLINE execCondT #-}++evalCondT :: Monad m => a -> CondT a m r -> m (Maybe r)+evalCondT a c = go `liftM` runCondT a c+  where+    go ((mr, _), _) = mr+{-# INLINE evalCondT #-}++-- | A specialized variant of 'runCondT' that simply returns True or False.+--+-- >>> let good = guard_ (== "foo.hs") :: Cond String ()+-- >>> let bad  = guard_ (== "foo.hi") :: Cond String ()+-- >>> runIdentity $ test "foo.hs" $ not_ bad >> return "Success"+-- True+-- >>> runIdentity $ test "foo.hs" $ not_ good >> return "Shouldn't reach here"+-- False+test :: Monad m => a -> CondT a m r -> m Bool+test a c = go `liftM` runCondT a c+  where+    go ((Nothing, _), _) = False+    go ((Just _, _), _)  = True+{-# INLINE test #-}+ -- | 'MonadQuery' is a custom version of 'MonadReader', created so that users -- could still have their own 'MonadReader' accessible within conditionals. class Monad m => MonadQuery a m | m -> a where     query :: m a     queries :: (a -> b) -> m b     update :: a -> m ()+    updates :: (a -> a) -> m ()  instance Monad m => MonadQuery a (CondT a m) where     -- | Returns the item currently under consideration.@@ -352,21 +380,27 @@     update a = CondT $ liftM accept' $ put a     {-# INLINE update #-} +    updates f = CondT $ liftM accept' $ modify f+    {-# INLINE updates #-}+ instance MonadQuery r m => MonadQuery r (ReaderT r m) where     query = lift query     queries = lift . queries     update = lift . update+    updates = lift . updates  instance (MonadQuery r m, Monoid w) => MonadQuery r (LazyRWS.RWST r w s m) where     query = lift query     queries = lift . queries     update = lift . update+    updates = lift . updates  instance (MonadQuery r m, Monoid w)          => MonadQuery r (StrictRWS.RWST r w s m) where     query = lift query     queries = lift . queries     update = lift . update+    updates = lift . updates  -- All of these instances need UndecidableInstances, because they do not satisfy -- the coverage condition.@@ -375,51 +409,61 @@     query   = lift query     queries = lift . queries     update = lift . update+    updates = lift . updates  instance (Error e, MonadQuery r m) => MonadQuery r (ErrorT e m) where     query   = lift query     queries = lift . queries     update = lift . update+    updates = lift . updates  instance MonadQuery r m => MonadQuery r (ExceptT e m) where     query   = lift query     queries = lift . queries     update = lift . update+    updates = lift . updates  instance MonadQuery r m => MonadQuery r (IdentityT m) where     query   = lift query     queries = lift . queries     update = lift . update+    updates = lift . updates  instance MonadQuery r m => MonadQuery r (ListT m) where     query   = lift query     queries = lift . queries     update = lift . update+    updates = lift . updates  instance MonadQuery r m => MonadQuery r (MaybeT m) where     query   = lift query     queries = lift . queries     update = lift . update+    updates = lift . updates  instance MonadQuery r m => MonadQuery r (Lazy.StateT s m) where     query   = lift query     queries = lift . queries     update = lift . update+    updates = lift . updates  instance MonadQuery r m => MonadQuery r (Strict.StateT s m) where     query   = lift query     queries = lift . queries     update = lift . update+    updates = lift . updates  instance (Monoid w, MonadQuery r m) => MonadQuery r (Lazy.WriterT w m) where     query   = lift query     queries = lift . queries     update = lift . update+    updates = lift . updates  instance (Monoid w, MonadQuery r m) => MonadQuery r (Strict.WriterT w m) where     query   = lift query     queries = lift . queries     update = lift . update+    updates = lift . updates  guardM :: MonadPlus m => m Bool -> m () guardM = (>>= guard)@@ -473,9 +517,9 @@ --   not.  This differs from simply stating the condition in that it itself --   always succeeds. ----- >>> flip runCond "foo.hs" $ matches (guard =<< queries (== "foo.hs"))+-- >>> runCond "foo.hs" $ matches (guard =<< queries (== "foo.hs")) -- Just True--- >>> flip runCond "foo.hs" $ matches (guard =<< queries (== "foo.hi"))+-- >>> runCond "foo.hs" $ matches (guard =<< queries (== "foo.hi")) -- Just False matches :: MonadPlus m => m r -> m Bool matches m = (const True `liftM` m) `mplus` return False@@ -487,9 +531,9 @@ -- -- >>> let good = guard_ (== "foo.hs") :: Cond String () -- >>> let bad  = guard_ (== "foo.hi") :: Cond String ()--- >>> flip runCond "foo.hs" $ if_ good (return "Success") (return "Failure")+-- >>> runCond "foo.hs" $ if_ good (return "Success") (return "Failure") -- Just "Success"--- >>> flip runCond "foo.hs" $ if_ bad (return "Success") (return "Failure")+-- >>> runCond "foo.hs" $ if_ bad (return "Success") (return "Failure") -- Just "Failure" if_ :: MonadPlus m => m r -> m s -> m s -> m s if_ c x y = matches c >>= \b -> if b then x else y@@ -500,9 +544,9 @@ -- -- >>> let good = guard_ (== "foo.hs") :: Cond String () -- >>> let bad  = guard_ (== "foo.hi") :: Cond String ()--- >>> flip runCond "foo.hs" $ when_ good ignore+-- >>> runCond "foo.hs" $ when_ good ignore -- Nothing--- >>> flip runCond "foo.hs" $ when_ bad ignore+-- >>> runCond "foo.hs" $ when_ bad ignore -- Just () when_ :: MonadPlus m => m r -> m s -> m () when_ c x = if_ c (x >> return ()) (return ())@@ -513,9 +557,9 @@ -- -- >>> let good = guard_ (== "foo.hs") :: Cond String () -- >>> let bad  = guard_ (== "foo.hi") :: Cond String ()--- >>> flip runCond "foo.hs" $ unless_ bad ignore+-- >>> runCond "foo.hs" $ unless_ bad ignore -- Nothing--- >>> flip runCond "foo.hs" $ unless_ good ignore+-- >>> runCond "foo.hs" $ unless_ good ignore -- Just () unless_ :: MonadPlus m => m r -> m s -> m () unless_ c x = if_ c (return ()) (x >> return ())@@ -526,9 +570,9 @@ -- -- >>> let good = guard_ (== "foo.hs") :: Cond String () -- >>> let bad  = guard_ (== "foo.hi") :: Cond String ()--- >>> flip runCond "foo.hs" $ or_ [bad, good]+-- >>> runCond "foo.hs" $ or_ [bad, good] -- Just ()--- >>> flip runCond "foo.hs" $ or_ [bad]+-- >>> runCond "foo.hs" $ or_ [bad] -- Nothing or_ :: MonadPlus m => [m r] -> m r or_ = Data.Foldable.msum@@ -539,9 +583,9 @@ -- -- >>> let good = guard_ (== "foo.hs") :: Cond String () -- >>> let bad  = guard_ (== "foo.hi") :: Cond String ()--- >>> flip runCond "foo.hs" $ and_ [bad, good]+-- >>> runCond "foo.hs" $ and_ [bad, good] -- Nothing--- >>> flip runCond "foo.hs" $ and_ [good]+-- >>> runCond "foo.hs" $ and_ [good] -- Just () and_ :: MonadPlus m => [m r] -> m () and_ = sequence_@@ -551,9 +595,9 @@ -- -- >>> let good = guard_ (== "foo.hs") :: Cond String () -- >>> let bad  = guard_ (== "foo.hi") :: Cond String ()--- >>> flip runCond "foo.hs" $ not_ bad >> return "Success"+-- >>> runCond "foo.hs" $ not_ bad >> return "Success" -- Just "Success"--- >>> flip runCond "foo.hs" $ not_ good >> return "Shouldn't reach here"+-- >>> runCond "foo.hs" $ not_ good >> return "Shouldn't reach here" -- Nothing not_ :: MonadPlus m => m r -> m () not_ c = if_ c ignore accept@@ -575,15 +619,3 @@ recurse :: Monad m => CondT a m r -> CondT a m r recurse c = CondT $ fmap (const (Recurse c)) `liftM` getCondT c {-# INLINE recurse #-}---- | A specialized variant of 'runCondT' that simply returns True or False.------ >>> let good = guard_ (== "foo.hs") :: Cond String ()--- >>> let bad  = guard_ (== "foo.hi") :: Cond String ()--- >>> runIdentity $ test "foo.hs" $ not_ bad >> return "Success"--- True--- >>> runIdentity $ test "foo.hs" $ not_ good >> return "Shouldn't reach here"--- False-test :: Monad m => a -> CondT a m r -> m Bool-test = (liftM isJust .) . flip runCondT-{-# INLINE test #-}
Pipes/Tree.hs view
@@ -6,11 +6,7 @@ import Control.Applicative import Control.Comonad.Trans.Cofree import Control.Cond-import Control.Exception-import Control.Monad import Pipes-import System.Directory-import System.Posix.Files  -- | A 'TreeT' is a tree of values, where the (possible) branches are -- 'ListT's.@@ -20,25 +16,6 @@ selectEach :: Monad m => m [a] -> ListT m a selectEach m = Select $ each =<< lift m --- | Return all files within a directory tree, hierarchically.-directoryFiles :: MonadIO m => FilePath -> TreeT m FilePath-directoryFiles path = CofreeT $ Select $ do-    eres <- liftIO $ try $ getDirectoryContents path-    case eres of-        Left (_ :: IOException) -> return ()-            -- liftIO $ putStrLn $-            --     "Error reading directory " ++ path ++ ": " ++ show e-        Right entries -> forM_ entries $ \entry ->-            unless (entry `elem` [".", ".."]) $ do-                let entryPath = path ++ "/" ++ entry-                estat <- liftIO $ try $ getFileStatus entryPath-                case estat of-                    Left (_ :: IOException) -> return ()-                    Right stat ->-                        yield (entryPath :< if isDirectory stat-                                            then Just (directoryFiles entryPath)-                                            else Nothing)- -- | Descend one level into a 'TreeT', yielding a list of values and their -- possible associated trees. descend :: Monad m => TreeT m a -> ListT m (a, Maybe (TreeT m a))@@ -73,7 +50,7 @@ -- @ winnow :: Monad m => TreeT m a -> CondT a m () -> TreeT m a winnow (CofreeT (Select t)) p = CofreeT $ Select $ for t $ \(a :< mst) -> do-    (mval, mnext) <- lift $ applyCondT a p+    (mval, mnext) <- lift $ execCondT a p     let mnext' = winnow <$> mst <*> mnext     case mval of         Nothing -> maybe (return ()) (enumerate . runCofreeT) mnext'
hierarchy.cabal view
@@ -1,5 +1,5 @@ name:          hierarchy-version:       0.2.1+version:       0.3.0 synopsis:      Pipes-based library for predicated traversal of generated trees description:   Pipes-based library for predicated traversal of generated trees homepage:      https://github.com/jwiegley/hierarchy@@ -12,11 +12,16 @@ build-type:    Simple cabal-version: >=1.10 +Source-repository head+  type: git+  location: git://github.com/jwiegley/hierarchy.git+ library+  ghc-options:      -Wall -O2 -funbox-strict-fields+  include-dirs:     .   exposed-modules:            Control.Cond     , Pipes.Tree-  ghc-options: -Wall   build-depends:              base                >=4.7  && <4.9     , transformers        >=0.3  && <0.5@@ -29,9 +34,6 @@     , semigroups          >=0.16 && <0.17     , free                >=4.12 && <4.13     , pipes               >=4.1  && <4.2-    , directory           >=1.2  && <1.3-    , unix                >=2.7  && <2.8-  -- hs-source-dirs:         default-language:    Haskell2010  Test-suite doctests@@ -56,8 +58,6 @@       base >=3     , hierarchy     , pipes              >=4.1  && <4.2-    , directory          >=1.2  && <1.3-    , unix               >=2.7  && <2.8     , transformers       >=0.3  && <0.5     , mtl                >=2.1  && <2.3     , hspec              >=1.4.4
test/Main.hs view
@@ -7,37 +7,9 @@ import Pipes.Prelude (toListM) import Pipes.Tree import Test.Hspec+import Test.Hspec.Expectations  main :: IO () main = hspec $ do     describe "Sanity tests" $ do-        it "Finds expected files in project" findsExpected--findsExpected :: Expectation-findsExpected = do-    let ignored = ["./.git", "./dist", "./result"]--    let files = winnow (directoryFiles ".") $ do-            path <- query-            liftIO $ putStrLn $ "Considering " ++ path-            when_ (guard_ (`elem` ignored)) $ do-                liftIO $ putStrLn $ "Pruning " ++ path-                prune-            -- equivalently we can say (but won't reach here now)...-            when (path `elem` ignored) $ do-                liftIO $ putStrLn $ "Pruning " ++ path-                prune--            guard_ (".hs" `isInfixOf`)--            -- We only reach the end if we have a file of interest,-            -- however any directories we didn't prune will still be-            -- descended into-            liftIO $ putStrLn "We found a Haskell file!"--    found <- toListM $ enumerate (walk files)-    sort found `shouldBe` [ "./Control/Cond.hs"-                          , "./Pipes/Tree.hs"-                          , "./Setup.hs"-                          , "./test/Main.hs"-                          , "./test/doctest.hs" ]+        it "No tests yet" $ True `shouldBe` True
test/doctest.hs view
@@ -10,6 +10,7 @@ main :: IO () main = getSources >>= \sources -> doctest $     "-iControl"+  : "-iPipes"   : "-idist/build/autogen"   : "-optP-include"   : "-optPdist/build/autogen/cabal_macros.h"@@ -17,7 +18,8 @@  getSources :: IO [FilePath] getSources =-    filter (\n -> ".hs" `isSuffixOf` n) <$> go "./Control"+    filter (\n -> ".hs" `isSuffixOf` n) <$>+        (liftA2 (++) (go "./Control") (go "./Pipes"))   where     go dir = do       (dirs, files) <- getFilesAndDirectories dir