diff --git a/.travis.yml b/.travis.yml
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,7 +2,7 @@
 
 env:
   - GHCVER=7.6.3
-  - GHCVER=7.8.1
+  - GHCVER=7.8.2
 
 matrix:
   allow_failures:
@@ -32,7 +32,7 @@
 
   # Update happy when building with GHC head
   - |
-    if [ $GHCVER = "head" ] || [ $GHCVER = "7.8.1" ]; then
+    if [ $GHCVER = "head" ] || [ $GHCVER = "7.8.2" ]; then
       $CABAL install happy alex
       export PATH=$HOME/.cabal/bin:$PATH
     fi
diff --git a/CHANGELOG.markdown b/CHANGELOG.markdown
--- a/CHANGELOG.markdown
+++ b/CHANGELOG.markdown
@@ -1,3 +1,8 @@
+0.1.0.1
+-------
+* `filepath` 1.4 support
+* `transformers` 0.4 support
+
 0.1
 ---
 * Repository initialized
diff --git a/search.cabal b/search.cabal
--- a/search.cabal
+++ b/search.cabal
@@ -1,6 +1,6 @@
 name:          search
 category:      Math, Topology, Search
-version:       0.1
+version:       0.1.0.1
 license:       BSD3
 cabal-version: >= 1.8
 license-file:  LICENSE
@@ -31,10 +31,11 @@
     profunctors          >= 4     && < 5,
     semigroupoids        >= 4     && < 5,
     tagged               >= 0.7   && < 1,
-    transformers         >= 0.3   && < 0.4
+    transformers         >= 0.3   && < 0.5
 
   exposed-modules:
     Data.Search
+    Data.Search.Intensional
 
   ghc-options: -Wall -fwarn-tabs -O2
   hs-source-dirs: src
@@ -49,5 +50,5 @@
     base,
     directory >= 1.0 && < 1.3,
     doctest   >= 0.8 && < 0.10,
-    filepath  >= 1.3 && < 1.4,
+    filepath  >= 1.3 && < 1.5,
     search
diff --git a/src/Data/Search/Intensional.hs b/src/Data/Search/Intensional.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Search/Intensional.hs
@@ -0,0 +1,198 @@
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE DefaultSignatures #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE Rank2Types #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE UndecidableInstances #-}
+module Data.Search.Intensional
+  ( Search(..)
+  , pessimumM
+  , optimum, pessimum
+  , optimalScore, pessimalScore
+  , cps
+  , union
+  , pair
+  , fromList
+  -- *  Hilbert's epsilon
+  , Hilbert(..)
+  , best, worst
+  , bestScore, worstScore
+  -- * Boolean-valued search
+  , every
+  , exists
+  ) where
+
+import Control.Applicative
+import Control.Monad.Trans.Cont
+import Control.Monad (ap)
+import Data.Function (on)
+import Data.Functor.Alt
+import Data.Functor.Bind
+import Data.Functor.Identity
+import Data.Int
+import Data.Monoid
+import Data.Ord
+import Data.Profunctor
+import Data.Proxy
+import Data.Tagged
+import Data.Typeable
+import Data.Word
+import GHC.Generics
+
+-- | Given a test that is required to execute in finite time for _all_ inputs, even infinite ones,
+-- 'Search' should productively yield an answer.
+--
+-- I currently also assume that comparison of scores can be done in finite time for all scores.
+--
+-- This rules out large score sets.
+--
+-- @'Search' 'Bool'@ can be used for predicate searches.
+newtype Search a b = Search { optimumM :: forall m. (Monad m, Applicative m) => (b -> m a) -> m b }
+  deriving Typeable
+
+optimum :: Search a b -> (b -> a) -> b
+optimum (Search k) f = runIdentity $ k (Identity . f)
+
+-- | Find the worst-scoring result of a search with monadic effects.
+pessimumM :: (Monad m, Applicative m) => Search (Down a) b -> (b -> m a) -> m b
+pessimumM = optimumM . lmap Down
+
+-- | Find the worst-scoring result of a search.
+pessimum :: Search (Down a) b -> (b -> a) -> b
+pessimum = optimum . lmap Down
+
+instance Profunctor Search where
+  dimap f g (Search k) = Search $ \p -> fmap g $ k $ fmap f . p . g
+  {-# INLINE dimap #-}
+
+instance Functor (Search a) where
+  fmap f (Search k) = Search $ \p -> fmap f $ k $ p . f
+  {-# INLINE fmap #-}
+
+instance Apply (Search a) where
+  (<.>) = (<*>)
+  {-# INLINE (<.>) #-}
+
+instance Applicative (Search a) where
+  pure a = Search $ \_ -> return a
+  (<*>) = ap
+
+instance Ord a => Alt (Search a) where
+  Search l <!> Search r = Search $ \p -> do
+    (a,b) <- (,) <$> l p <*> r p
+    (\ma mb -> if ma >= mb then a else b) <$> p a <*> p b
+
+instance Bind (Search a) where
+  (>>-) = (>>=)
+
+instance Monad (Search a) where
+  return a = Search $ \_ -> return a
+  m >>= k = jn (fmap k m) where
+    jn x = Search $ \p -> do
+      z <- optimumM x $ \ y -> optimumM y p >>= p
+      optimumM z p
+
+-- | <http://en.wikipedia.org/wiki/Epsilon_calculus#Hilbert_notation Hilbert's epsilon>
+class Hilbert a b where
+  epsilon :: Search a b
+  default epsilon :: (GHilbert a (Rep b), Generic b) => Search a b
+  epsilon = to <$> gepsilon
+
+-- | Generic derivation of Hilbert's epsilon.
+class GHilbert a f where
+  gepsilon :: Search a (f b)
+
+instance GHilbert a U1 where
+  gepsilon = pure U1
+
+instance (GHilbert a f, GHilbert a g) => GHilbert a (f :*: g) where
+  gepsilon = liftA2 (:*:) gepsilon gepsilon
+
+instance (GHilbert a f, GHilbert a g, Ord a) => GHilbert a (f :+: g) where
+  gepsilon = L1 <$> gepsilon <!> R1 <$> gepsilon
+
+instance Hilbert a b => GHilbert a (K1 i b) where
+  gepsilon = K1 <$> epsilon
+
+instance GHilbert a f => GHilbert a (M1 i c f) where
+  gepsilon = M1 <$> gepsilon
+
+instance Hilbert x ()
+instance Hilbert x (Proxy a) where epsilon = pure Proxy
+instance Hilbert x a => Hilbert x (Tagged s a) where epsilon = Tagged <$> epsilon
+instance (Hilbert x a, Hilbert x b) => Hilbert x (a, b)
+instance (Hilbert x a, Hilbert x b, Hilbert x c) => Hilbert x (a, b, c)
+instance (Hilbert x a, Hilbert x b, Hilbert x c, Hilbert x d) => Hilbert x (a, b, c, d)
+instance (Hilbert x a, Hilbert x b, Hilbert x c, Hilbert x d, Hilbert x e) => Hilbert x (a, b, c, d, e)
+instance Ord x => Hilbert x Bool
+instance Ord x => Hilbert x Any where epsilon = Any <$> epsilon
+instance Ord x => Hilbert x All where epsilon = All <$> epsilon
+instance Hilbert x a => Hilbert x (Product a) where epsilon = Product <$> epsilon
+instance Hilbert x a => Hilbert x (Sum a) where epsilon = Sum <$> epsilon
+instance Ord x => Hilbert x Ordering
+instance Ord x => Hilbert x Char where epsilon = fromList [minBound .. maxBound]
+instance Ord x => Hilbert x Int8 where epsilon = fromList [minBound .. maxBound]
+instance Ord x => Hilbert x Int16 where epsilon = fromList [minBound .. maxBound]
+instance Ord x => Hilbert x Word8 where epsilon = fromList [minBound .. maxBound]
+instance Ord x => Hilbert x Word16 where epsilon = fromList [minBound .. maxBound]
+instance (Ord x, Hilbert x a) => Hilbert x [a]
+instance (Ord x, Hilbert x a) => Hilbert x (ZipList a) where epsilon = ZipList <$> epsilon
+instance (Ord x, Hilbert x a) => Hilbert x (Maybe a)
+instance (Ord x, Hilbert x a) => Hilbert x (First a) where epsilon = First <$> epsilon
+instance (Ord x, Hilbert x a) => Hilbert x (Last a) where epsilon = Last <$> epsilon
+instance (Ord x, Hilbert x a, Hilbert x b) => Hilbert x (Either a b)
+instance (Ord x, Ord a, Hilbert x b) => Hilbert x (Search a b) where
+  epsilon = fromList <$> epsilon
+
+-- | What is the best score obtained by the search?
+optimalScore :: Search a b -> (b -> a) -> a
+optimalScore m p = p (optimum m p)
+
+-- | What is the worst score obtained by the search?
+pessimalScore :: Search (Down a) b -> (b -> a) -> a
+pessimalScore m p = p (pessimum m p)
+
+-- | search for an optimal answer using Hilbert's epsilon
+--
+-- >>> search (>4) :: Int8
+-- 5
+best :: Hilbert a b => (b -> a) -> b
+best = optimum epsilon
+
+-- | What is the worst scoring answer by Hilbert's epsilon?
+worst :: Hilbert (Down a) b => (b -> a) -> b
+worst = pessimum epsilon
+
+bestScore :: Hilbert a b => (b -> a) -> a
+bestScore = optimalScore epsilon
+
+worstScore :: Hilbert (Down a) b => (b -> a) -> a
+worstScore = pessimalScore epsilon
+
+-- | does there exist an element satisfying the predicate?
+--
+-- >>> exists (>(maxBound::Int8))
+-- False
+--
+exists :: Hilbert Bool b => (b -> Bool) -> Bool
+exists = bestScore
+
+every :: Hilbert Bool b => (b -> Bool) -> Bool
+every p = not.p $ best $ not.p
+
+union :: Ord a => Search a b -> Search a b -> Search a b
+union = (<!>)
+
+pair :: Ord a => b -> b -> Search a b
+pair = on (<!>) pure
+
+fromList :: Ord a => [b] -> Search a b
+fromList = foldr1 (<!>) . map return
+
+-- | 'Search' is more powerful than 'Cont'.
+--
+-- This provides a canonical monad homomorphism into 'Cont'.
+cps :: Search a b -> Cont a b
+cps = cont . optimalScore
