diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2012-2014 Tony Morris
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of the author nor the names of his contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,3 @@
+import Distribution.Simple
+main = defaultMain
+
diff --git a/filepather.cabal b/filepather.cabal
new file mode 100644
--- /dev/null
+++ b/filepather.cabal
@@ -0,0 +1,48 @@
+Name:               filepather
+Version:            0.3.0
+Author:             Tony Morris <ʇǝu˙sıɹɹoɯʇ@ןןǝʞsɐɥ>
+Maintainer:         Tony Morris <ʇǝu˙sıɹɹoɯʇ@ןןǝʞsɐɥ>
+Copyright:          Tony Morris
+License:            BSD3
+License-File:       LICENSE
+Synopsis:           Functions on System.FilePath
+Category:           System
+Description:
+  Functions over @System.FilePath@ including a find function for recursing down directories.
+Homepage:           https://github.com/tonymorris/filepather
+Cabal-version:      >= 1.6
+Build-Type:         Simple
+
+Flag                small_base
+  Description:      Choose the new, split-up base package.
+
+Library
+  Build-Depends:
+                    base < 5 && >= 3,
+                    directory >= 1.1,
+                    filepath >= 1.2,
+                    mtl >= 2,
+                    comonad >= 1.1,
+                    transformers >= 0.2,
+                    data-lens >= 2.9,
+                    comonad-transformers >= 2
+
+  GHC-Options:
+                    -Wall
+
+  Hs-Source-Dirs:
+                    src
+
+  Exposed-Modules:
+                    System.FilePath.FilePather
+                    System.FilePath.FilePather.FileType
+                    System.FilePath.FilePather.RecursePredicate
+                    System.FilePath.FilePather.FilterPredicate
+                    System.FilePath.FilePather.FilePathPredicate
+                    System.FilePath.FilePather.Find
+                    System.FilePath.FilePather.LiftI
+
+Source-Repository  head
+  type: git
+  location: git@github.com:tonymorris/filepather.git
+
diff --git a/src/System/FilePath/FilePather.hs b/src/System/FilePath/FilePather.hs
new file mode 100644
--- /dev/null
+++ b/src/System/FilePath/FilePather.hs
@@ -0,0 +1,9 @@
+module System.FilePath.FilePather(module X) where
+
+import System.FilePath.FilePather.FileType as X
+import System.FilePath.FilePather.RecursePredicate as X
+import System.FilePath.FilePather.FilterPredicate as X
+import System.FilePath.FilePather.FilePathPredicate as X
+import System.FilePath.FilePather.Find as X
+import System.FilePath.FilePather.LiftI as X
+
diff --git a/src/System/FilePath/FilePather/FilePathPredicate.hs b/src/System/FilePath/FilePather/FilePathPredicate.hs
new file mode 100644
--- /dev/null
+++ b/src/System/FilePath/FilePather/FilePathPredicate.hs
@@ -0,0 +1,270 @@
+module System.FilePath.FilePather.FilePathPredicate
+(
+  FilePathPredicate(..)
+) where
+
+import qualified System.FilePath as P
+import System.FilePath.FilePather.RecursePredicate
+import System.FilePath.FilePather.FilterPredicate
+import Control.Monad
+import qualified Data.Foldable as F
+
+-- | Functions that are common to predicates that work on 'FilePath' values.
+class FilePathPredicate f where
+  -- | A predicate that always succeeds.
+  always ::
+    Monad g =>
+    f g
+  -- | A predicate that always fails.
+  never ::
+    Monad g =>
+    f g
+  -- | Return a predicate that succeeds only if the two given predicates succeed.
+  (.&&.) ::
+    Monad g =>
+    f g
+    -> f g
+    -> f g
+  -- | Return a predicate that succeeds if any of the two given predicates succeed.
+  (.||.) ::
+    Monad g =>
+    f g
+    -> f g
+    -> f g
+  -- | Negates the given predicate.
+  (.!.) ::
+    Monad g =>
+    f g
+    -> f g
+  -- | Folds the predicates on disjunction.
+  anyof ::
+    (F.Foldable t, Monad g) =>
+    t (f g)
+    -> f g
+  -- | Folds the predicates on conjunction.
+  anyof =
+    F.foldr (.||.) never
+  allof ::
+    (F.Foldable t, Monad g) =>
+    t (f g)
+    -> f g
+  allof =
+    F.foldr (.&&.) always
+  -- | A predicate that computes its result based on a file name extension.
+  extension ::
+    Monad g =>
+    (FilePath -> Bool)
+    -> f g
+  -- | A predicate that computes its result based on equivalence to a file name extension. This function matches with and without the preceding extension separator (.).
+  extensionEq ::
+    Monad g =>
+    FilePath
+    -> f g
+  extensionEq p =
+    extension (== p)
+  -- | A predicate that computes its result based on equivalence to one of a list of file name extensions.
+  extensionOneof ::
+    (F.Foldable t, Monad g) =>
+    t FilePath
+    -> f g
+  extensionOneof =
+    F.foldr (\a b -> extensionEq a .||. b) never
+  -- | A predicate that computes its result based on inequivalence to any of a list of file name extensions.
+  extensionNoneof ::
+    (F.Foldable t, Monad g) =>
+    t FilePath
+    -> f g
+  extensionNoneof =
+    F.foldr (\a b -> (.!.) (extensionEq a) .&&. b) always
+  -- | A predicate that computes its result based on a directory.
+  directory ::
+    Monad g =>
+    (FilePath -> Bool)
+    -> f g
+  -- | A predicate that succeeds if its 'FilePath' has an extension.
+  hasExtension ::
+    Monad g =>
+    f g
+  hasExtension =
+    (.!.) notHasExtension
+  -- | A predicate that succeeds if its 'FilePath' does not have an extension.
+  notHasExtension ::
+    Monad g =>
+    f g
+  notHasExtension =
+    (.!.) hasExtension
+  -- | A predicate that computes its result based on the splitting of a name and extension.
+  splitExtension ::
+    Monad g =>
+    (String -> String -> Bool)
+    -> f g
+  -- | A predicate that computes its result based on the splitting of a name into directories.
+  splitDirectories ::
+    Monad g =>
+    ([FilePath] -> Bool)
+    -> f g
+  -- | A predicate that succeeds if its 'FilePath' has a trailing path separator.
+  hasTrailingPathSeparator ::
+    Monad g =>
+    f g
+  hasTrailingPathSeparator =
+    (.!.) notHasTrailingPathSeparator
+  -- | A predicate that succeeds if its 'FilePath' does not have a trailing path separator.
+  notHasTrailingPathSeparator::
+    Monad g =>
+    f g
+  notHasTrailingPathSeparator =
+    (.!.) hasTrailingPathSeparator
+  -- | A predicate that computes its result based on the file name.
+  fileName ::
+    Monad g =>
+    (FilePath -> Bool)
+    -> f g
+  -- | A predicate that computes its result based on the base name.
+  baseName ::
+    Monad g =>
+    (FilePath -> Bool)
+    -> f g
+  -- | A predicate that computes its result based on the normalised file name.
+  normalise ::
+    Monad g =>
+    (FilePath -> Bool)
+    -> f g
+  -- | A predicate that computes its result based on the file name having been made valid.
+  makeValid ::
+    Monad g =>
+    (FilePath -> Bool)
+    -> f g
+  -- | A predicate that succeeds if its 'FilePath' is relative.
+  isRelative ::
+    Monad g =>
+    f g
+  isRelative =
+    (.!.) isNotRelative
+  -- | A predicate that succeeds if its 'FilePath' is not relative.
+  isNotRelative ::
+    Monad g =>
+    f g
+  isNotRelative =
+    (.!.) isRelative
+  -- | A predicate that succeeds if its 'FilePath' is absolute.
+  isAbsolute ::
+    Monad g =>
+    f g
+  isAbsolute =
+    (.!.) isNotAbsolute
+  -- | A predicate that succeeds if its 'FilePath' is not absolute.
+  isNotAbsolute ::
+    Monad g =>
+    f g
+  isNotAbsolute =
+    (.!.) isAbsolute
+  -- | A predicate that succeeds if its 'FilePath' is valid.
+  isValid ::
+    Monad g =>
+    f g
+  isValid =
+    (.!.) isNotValid
+  -- | A predicate that succeeds if its 'FilePath' is not valid.
+  isNotValid ::
+    Monad g =>
+    f g
+  isNotValid =
+    (.!.) isValid
+
+instance FilePathPredicate RecursePredicateT where
+  always =
+    recursePredicateT . const . return $ True
+  never =
+    recursePredicateT . const . return $ False
+  f .&&. g =
+    recursePredicateT $ \p -> do r <- runRecursePredicateT f p
+                                 if r
+                                   then
+                                     runRecursePredicateT g p
+                                   else
+                                     return False
+  f .||. g =
+    recursePredicateT $ \p -> do r <- runRecursePredicateT f p
+                                 if r
+                                   then
+                                     return True
+                                   else
+                                     runRecursePredicateT g p
+  (.!.) f =
+    recursePredicateT $ liftM not . runRecursePredicateT f
+  extension f = 
+    recursePredicateT $ return . liftM2 (||) f (f . drop 1) . P.takeExtension
+  directory f = 
+    recursePredicateT $ return . f . P.takeDirectory
+  hasExtension =
+    recursePredicateT $ return . P.hasExtension
+  splitExtension f =
+    recursePredicateT $ return . uncurry f . P.splitExtension
+  splitDirectories f = 
+    recursePredicateT $ return . f . P.splitDirectories
+  hasTrailingPathSeparator =
+    recursePredicateT $ return . P.hasTrailingPathSeparator
+  fileName f = 
+    recursePredicateT $ return . f . P.takeFileName
+  baseName f = 
+    recursePredicateT $ return . f . P.takeBaseName
+  normalise f = 
+    recursePredicateT $ return . f . P.normalise
+  makeValid f = 
+    recursePredicateT $ return . f . P.makeValid
+  isRelative =
+    recursePredicateT $ return . P.isRelative
+  isAbsolute =
+    recursePredicateT $ return . P.isAbsolute
+  isValid =
+    recursePredicateT $ return . P.isValid
+
+instance FilePathPredicate FilterPredicateT where
+  always =
+    filterPredicateT . const . const . return $ True
+  never =
+    filterPredicateT . const . const . return $ False
+  f .&&. g =
+    filterPredicateT $ \p k -> do r <- runFilterPredicateT f p k
+                                  if r
+                                    then
+                                      runFilterPredicateT g p k
+                                    else
+                                      return False
+  f .||. g =
+    filterPredicateT $ \p k -> do r <- runFilterPredicateT f p k
+                                  if r
+                                    then
+                                      return True
+                                    else
+                                      runFilterPredicateT g p k
+  (.!.) f =
+    filterPredicateT $ \p -> liftM not . runFilterPredicateT f p
+  extension f = 
+    filterPredicateT $ const . return . liftM2 (||) f (f . drop 1) . P.takeExtension
+  directory f = 
+    filterPredicateT $ const . return . f . P.takeDirectory
+  hasExtension =
+    filterPredicateT $ const . return . P.hasExtension
+  splitExtension f =
+    filterPredicateT $ const . return . uncurry f . P.splitExtension
+  splitDirectories f = 
+    filterPredicateT $ const . return . f . P.splitDirectories
+  hasTrailingPathSeparator =
+    filterPredicateT $ const . return . P.hasTrailingPathSeparator
+  fileName f = 
+    filterPredicateT $ const . return . f . P.takeFileName
+  baseName f = 
+    filterPredicateT $ const . return . f . P.takeBaseName
+  normalise f = 
+    filterPredicateT $ const . return . f . P.normalise
+  makeValid f = 
+    filterPredicateT $ const . return . f . P.makeValid
+  isRelative =
+    filterPredicateT $ const . return . P.isRelative
+  isAbsolute =
+    filterPredicateT $ const . return . P.isAbsolute
+  isValid =
+    filterPredicateT $ const . return . P.isValid
+
diff --git a/src/System/FilePath/FilePather/FileType.hs b/src/System/FilePath/FilePather/FileType.hs
new file mode 100644
--- /dev/null
+++ b/src/System/FilePath/FilePather/FileType.hs
@@ -0,0 +1,32 @@
+module System.FilePath.FilePather.FileType
+(
+  FileType(..)
+, isFile
+, isDirectory
+, isUnknown
+) where
+-- | The possible types of a file.
+data FileType =
+  File -- ^ The type is a normal file.
+  | Directory -- ^ The type is a directory.
+  | Unknown -- ^ The type is unknown.
+  deriving (Eq, Ord, Show, Enum)
+
+isFile ::
+  FileType
+  -> Bool
+isFile =
+  (==) File
+
+isDirectory ::
+  FileType
+  -> Bool
+isDirectory =
+  (==) Directory
+
+isUnknown ::
+  FileType
+  -> Bool
+isUnknown =
+  (==) Unknown
+
diff --git a/src/System/FilePath/FilePather/FilterPredicate.hs b/src/System/FilePath/FilePather/FilterPredicate.hs
new file mode 100644
--- /dev/null
+++ b/src/System/FilePath/FilePather/FilterPredicate.hs
@@ -0,0 +1,88 @@
+module System.FilePath.FilePather.FilterPredicate
+(
+  FilterPredicateT
+, FilterPredicate
+, filterPredicateT
+, filterPredicate
+, filterPredicateT'
+, filterPredicate'
+, runFilterPredicateT
+, runFilterPredicate
+, isDirectoryType
+, isFileType
+, isUnknownType
+) where
+
+import Control.Monad.Identity
+import System.FilePath.FilePather.FileType
+
+newtype FilterPredicateT f =
+  FilterPredicateT (FilePath -> FileType -> f Bool)
+
+-- | A filter predicate that does not require effects to compute its result.
+type FilterPredicate =
+  FilterPredicateT Identity
+
+-- | A filter predicate takes a 'FilePath' and a file type and returns whether or not to filter the value.
+filterPredicateT ::
+  (FilePath -> FileType -> f Bool)
+  -> FilterPredicateT f
+filterPredicateT =
+  FilterPredicateT
+
+-- | Construct a filter predicate that does not require effects to compute its result.
+filterPredicate ::
+  (FilePath -> FileType -> Bool)
+  -> FilterPredicate
+filterPredicate f =
+  filterPredicateT (\z -> Identity . f z)
+
+-- | A filter predicate takes a 'FilePath' and returns whether or not to filter the value.
+filterPredicateT' ::
+  (FilePath -> f Bool)
+  -> FilterPredicateT f
+filterPredicateT' f =
+  filterPredicateT (const . f)
+
+-- | Construct a filter predicate that does not require effects to compute its result.
+filterPredicate' ::
+  (FilePath -> Bool)
+  -> FilterPredicate
+filterPredicate' f =
+  filterPredicate (const . f)
+
+-- | Extract the filter predicate function.
+runFilterPredicateT ::
+  FilterPredicateT f
+  -> FilePath
+  -> FileType
+  -> f Bool
+runFilterPredicateT (FilterPredicateT f) =
+  f
+
+-- | Construct a filter predicate that does not require effects to compute its result.
+runFilterPredicate ::
+  FilterPredicate
+  -> FilePath
+  -> FileType
+  -> Bool
+runFilterPredicate p k =
+  runIdentity . runFilterPredicateT p k
+
+isDirectoryType ::
+  Monad f =>
+  FilterPredicateT f
+isDirectoryType =
+  filterPredicateT . const $ return . isDirectory
+
+isFileType ::
+  Monad f =>
+  FilterPredicateT f
+isFileType =
+  filterPredicateT . const $ return . isFile
+
+isUnknownType ::
+  Monad f =>
+  FilterPredicateT f
+isUnknownType =
+  filterPredicateT . const $ return . isUnknown
diff --git a/src/System/FilePath/FilePather/Find.hs b/src/System/FilePath/FilePather/Find.hs
new file mode 100644
--- /dev/null
+++ b/src/System/FilePath/FilePather/Find.hs
@@ -0,0 +1,255 @@
+module System.FilePath.FilePather.Find
+(
+  Find(..)
+, findi
+, findpi
+, FindR
+, foundR
+, dropR
+, recurseR
+, noRecurseR
+, foundL
+, dropL
+, recurseL
+, noRecurseL
+) where
+
+import Control.Monad.Identity
+import Control.Monad.Trans.Identity
+import Control.Comonad
+import Control.Comonad.Trans.Store
+import Data.Lens.Partial.Common hiding (null)
+import System.FilePath
+import System.FilePath.FilePather.RecursePredicate
+import System.FilePath.FilePather.FilterPredicate
+import System.FilePath.FilePather.FileType
+import System.Directory
+
+class Find f where
+  -- | Finds all files using the given recurse predicate and filter predicate in the given file path.
+  find ::
+    FilterPredicateT f
+    -> RecursePredicateT f
+    -> FilePath
+    -> IO [FindR]
+  -- | Find files in the current directory.
+  findHere ::
+    FilterPredicateT f
+    -> RecursePredicateT f
+    -> IO [FindR]
+  findHere f r =
+    getCurrentDirectory >>= find f r
+  -- | Finds all files using the given recurse predicate and filter predicate in the given file path.
+  findp ::
+    FilterPredicateT f
+    -> RecursePredicateT f
+    -> FilePath
+    -> IO [FilePath]
+  findp f r =
+    liftM (\x -> x >>= \w ->
+      case w of
+        Found p _   -> [p]
+        Drop _ _    -> []
+        Recurse _   -> []
+        NoRecurse _ -> []) . find f r
+  -- | Find files in the current directory.
+  findpHere ::
+    FilterPredicateT f
+    -> RecursePredicateT f
+    -> IO [FilePath]
+  findpHere f r =
+    getCurrentDirectory >>= findp f r
+
+instance Find Identity where
+  find f' r' =
+    let find' base p =
+          let f =
+                runFilterPredicateT f'
+              r =
+                runRecursePredicateT r'
+              z ::
+                FilePath
+              z =
+                if null base then p else base </> p
+              keep ::
+                Bool
+                -> FileType
+                -> FindR
+              keep u =
+                (if u then Found else Drop) z
+              rkeep ::
+                Bool
+                -> FindR
+              rkeep u =
+                (if u then Recurse else NoRecurse) z
+              tkeep ::
+                FileType
+                -> [FindR]
+              tkeep t =
+                [keep (runIdentity (f z t)) t]
+          in do fe <- doesFileExist z
+                if fe
+                  then
+                    return (tkeep File)
+                  else
+                    do de <- doesDirectoryExist z
+                       if de
+                         then
+                           let (Identity k) = f z Directory
+                               (Identity l) = r z
+                           in liftM ([rkeep l, keep k Directory] ++) $
+                                if l
+                                  then
+                                    do t <- getDirectoryContents z
+                                       u <- forM (filter (`notElem` [".", ".."]) t) (find f' r' . (z </>))
+                                       return (concat u)
+                                  else
+                                    return []
+                         else
+                           return (tkeep Unknown)
+    in find' []
+
+instance Find IO where
+  find f' r' =
+    let find' base p =
+          let f =
+                runFilterPredicateT f'
+              r =
+                runRecursePredicateT r'
+              z ::
+                FilePath
+              z =
+                if null base then p else base </> p
+              keep ::
+                Bool
+                -> FileType
+                -> FindR
+              keep u =
+                (if u then Found else Drop) z
+              rkeep ::
+                Bool
+                -> FindR
+              rkeep u =
+                (if u then Recurse else NoRecurse) z
+              tkeep ::
+                FileType
+                -> IO [FindR]
+              tkeep t =
+                f z t >>= \y -> return [keep y t]
+          in do fe <- doesFileExist z
+                if fe
+                  then
+                    tkeep File
+                  else
+                    do de <- doesDirectoryExist z
+                       if de
+                         then
+                           do k <- f z Directory
+                              l <- r z
+                              liftM ([rkeep l, keep k Directory] ++) $
+                                if l
+                                  then
+                                    do t <- getDirectoryContents z
+                                       u <- forM (filter (`notElem` [".", ".."]) t) (find f' r' . (z </>))
+                                       return (concat u)
+                                  else
+                                    return []
+                         else
+                           tkeep Unknown
+    in find' []
+
+instance Comonad f => Find (IdentityT f) where
+  find f r =
+    find (filterPredicateT $ \p -> Identity . extract . runFilterPredicateT f p) (recursePredicateT $ Identity . extract . runRecursePredicateT r)
+
+-- | A specialisation of `find` to the `Identity` monad. Useful in assisting type-inference.
+findi ::
+  FilterPredicate
+  -> RecursePredicate
+  -> FilePath
+  -> IO [FindR]
+findi =
+  find
+
+-- | A specialisation of `findp` to the `Identity` monad. Useful in assisting type-inference.
+findpi ::
+  FilterPredicate
+  -> RecursePredicate
+  -> FilePath
+  -> IO [FilePath]
+findpi =
+  findp
+
+-- | The results of a path find. One of
+--
+-- * @found@ with the file path name and file type.
+--
+-- * @drop@ with the file path name and file type.
+--
+-- * @recurse@ with the file path (the file type is always directory).
+--
+-- * @no-recurse@ with the file path (the file type is always directory).
+data FindR =
+  Found FilePath FileType
+  | Drop FilePath FileType
+  | Recurse FilePath
+  | NoRecurse FilePath
+  deriving (Eq, Show)
+
+foundR ::
+  FilePath
+  -> FileType
+  -> FindR
+foundR =
+  Found
+
+dropR ::
+  FilePath
+  -> FileType
+  -> FindR
+dropR =
+  Drop
+
+recurseR ::
+  FilePath
+  -> FindR
+recurseR =
+  Recurse
+
+noRecurseR ::
+  FilePath
+  -> FindR
+noRecurseR =
+  NoRecurse
+
+foundL ::
+  PartialLens FindR (FilePath, FileType)
+foundL =
+  PLens $ \r ->
+    case r of
+      Found p t -> Just (store (uncurry Found) (p, t))
+      _         -> Nothing
+
+dropL ::
+  PartialLens FindR (FilePath, FileType)
+dropL =
+  PLens $ \r ->
+    case r of
+      Drop p t -> Just (store (uncurry Drop) (p, t))
+      _        -> Nothing
+
+recurseL ::
+  PartialLens FindR FilePath
+recurseL =
+  PLens $ \r ->
+    case r of
+      Recurse p -> Just (store Recurse p)
+      _         -> Nothing
+
+noRecurseL ::
+  PartialLens FindR FilePath
+noRecurseL =
+  PLens $ \r ->
+    case r of
+      NoRecurse p -> Just (store NoRecurse p)
+      _           -> Nothing
diff --git a/src/System/FilePath/FilePather/LiftI.hs b/src/System/FilePath/FilePather/LiftI.hs
new file mode 100644
--- /dev/null
+++ b/src/System/FilePath/FilePather/LiftI.hs
@@ -0,0 +1,26 @@
+{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies #-}
+
+module System.FilePath.FilePather.LiftI
+(
+  LiftI(..)
+) where
+
+import System.FilePath.FilePather.RecursePredicate
+import System.FilePath.FilePather.FilterPredicate
+
+-- | A type-class for lifting a value.
+-- This type-class probably belongs elsewhere (pointers appreciated!).
+class LiftI f a | f -> a where
+  liftI ::
+    Monad g =>
+    g a
+    -> f g
+
+instance LiftI RecursePredicateT Bool where
+  liftI = 
+    recursePredicateT . const
+
+instance LiftI FilterPredicateT Bool where
+  liftI = 
+    filterPredicateT . const . const
+
diff --git a/src/System/FilePath/FilePather/RecursePredicate.hs b/src/System/FilePath/FilePather/RecursePredicate.hs
new file mode 100644
--- /dev/null
+++ b/src/System/FilePath/FilePather/RecursePredicate.hs
@@ -0,0 +1,59 @@
+module System.FilePath.FilePather.RecursePredicate
+(
+  RecursePredicateT
+, RecursePredicate
+, recursePredicateT
+, recursePredicate
+, runRecursePredicateT
+, runRecursePredicate
+, toFilterPredicate
+) where
+
+import Control.Monad.Identity
+import System.FilePath.FilePather.FilterPredicate
+
+-- | A recurse predicate takes a 'FilePath', which is a directory, and returns whether or not to continue recursing down on that directory.
+newtype RecursePredicateT f =
+  RecursePredicateT (FilePath -> f Bool)
+
+-- | A recurse predicate that does not require effects to compute its result.
+type RecursePredicate =
+  RecursePredicateT Identity
+
+-- | Construct a recurse predicate. The most general construction function.
+recursePredicateT ::
+  (FilePath -> f Bool)
+  -> RecursePredicateT f
+recursePredicateT =
+  RecursePredicateT
+
+-- | Construct a recurse predicate that does not require effects to compute its result.
+recursePredicate ::
+  (FilePath -> Bool)
+  -> RecursePredicate
+recursePredicate f =
+  recursePredicateT (Identity . f)
+
+-- | Extract the recurse predicate function.
+runRecursePredicateT ::
+  RecursePredicateT f
+  -> FilePath
+  -> f Bool
+runRecursePredicateT (RecursePredicateT f) =
+  f
+
+-- | Extract the recurse predicate function that does not require effects to compute its result.
+runRecursePredicate ::
+  RecursePredicate
+  -> FilePath
+  -> Bool
+runRecursePredicate p =
+  runIdentity . runRecursePredicateT p
+
+-- | Convert the recurse predicate to a filter predicate.
+toFilterPredicate ::
+  RecursePredicateT f
+  -> FilterPredicateT f
+toFilterPredicate (RecursePredicateT f) =
+  filterPredicateT (const . f)
+
