diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -25,18 +25,18 @@
 import Network.Wai.Handler.Warp
 
 main :: IO ()
-main = run 8080 (route start)
+main = run 8080 (route (prepare start))
 
-start :: Monad m => Routes m ()
+start :: Monad m => Routes a m ()
 start = do
     get "/user/:name" fetchUser $
-        Capture "name"
+        capture "name"
 
     get "/user/find" findUser $
-        Query "byName" :||: Query "byId"
+        query "byName" :||: query "byId"
 
     delete "/user/:name" rmUser $
-        Capture "name" :&: Opt (Cookie "foo")
+        capture "name" :&: opt (cookie "foo")
 
 fetchUser :: Monad m => Text -> m Response
 fetchUser name = ...
diff --git a/examples/eval-routing.hs b/examples/eval-routing.hs
--- a/examples/eval-routing.hs
+++ b/examples/eval-routing.hs
@@ -1,4 +1,5 @@
-{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE TypeOperators     #-}
 
 -- Like "direct.hs" but makes use of wai-routing.
 
@@ -27,10 +28,10 @@
         _   -> fail $ "Invalid operation: " ++ show c
 
 main :: IO ()
-main = run 8080 $ logStdout (route start)
+main = run 8080 $ logStdout (route (prepare start))
 
-start :: Monad m => Routes m ()
-start = get "eval" eval (Query "x" :&: Query "y" :&: Query "f")
+start :: Monad m => Routes a m ()
+start = get "eval" eval (query "x" :&: query "y" :&: query "f")
 
 eval :: Monad m => Int ::: Int ::: Op -> m Response
 eval (x ::: y ::: f) = respond status200 . fromString . show $
diff --git a/src/Network/Wai/Routing/Predicate/Accept.hs b/src/Network/Wai/Routing/Predicate/Accept.hs
--- a/src/Network/Wai/Routing/Predicate/Accept.hs
+++ b/src/Network/Wai/Routing/Predicate/Accept.hs
@@ -8,7 +8,8 @@
 {-# LANGUAGE TypeFamilies          #-}
 
 module Network.Wai.Routing.Predicate.Accept
-    ( Accept (..)
+    ( Accept
+    , accept
     , module Network.Wai.Routing.MediaType
     ) where
 
@@ -28,6 +29,10 @@
 
 -- | A 'Predicate' against the 'Request's \"Accept\" header.
 data Accept (t :: Symbol) (s :: Symbol) = Accept
+
+accept :: Accept t s
+accept = Accept
+{-# INLINABLE accept #-}
 
 type1 :: SingI t => Accept t s -> ByteString
 type1 m = withSing (f m)
diff --git a/src/Network/Wai/Routing/Predicate/Capture.hs b/src/Network/Wai/Routing/Predicate/Capture.hs
--- a/src/Network/Wai/Routing/Predicate/Capture.hs
+++ b/src/Network/Wai/Routing/Predicate/Capture.hs
@@ -19,8 +19,10 @@
 -- extracts from a request path whatever is given for @:name@
 -- and @:street@.
 module Network.Wai.Routing.Predicate.Capture
-    ( Capture    (..)
-    , HasCapture (..)
+    ( Capture
+    , HasCapture
+    , capture
+    , hasCapture
     ) where
 
 import Data.ByteString (ByteString)
@@ -34,6 +36,10 @@
 
 newtype Capture a = Capture ByteString
 
+capture :: ByteString -> Capture a
+capture = Capture
+{-# INLINABLE capture #-}
+
 instance (FromByteString a) => Predicate (Capture a) Req where
     type FVal (Capture a) = Error
     type TVal (Capture a) = a
@@ -42,6 +48,10 @@
         rqApply (lookupCapture x) readValues (err status400 msg)
 
 newtype HasCapture = HasCapture ByteString
+
+hasCapture :: ByteString -> HasCapture
+hasCapture = HasCapture
+{-# INLINABLE hasCapture #-}
 
 instance Predicate HasCapture Req where
     type FVal HasCapture   = Error
diff --git a/src/Network/Wai/Routing/Predicate/Content.hs b/src/Network/Wai/Routing/Predicate/Content.hs
--- a/src/Network/Wai/Routing/Predicate/Content.hs
+++ b/src/Network/Wai/Routing/Predicate/Content.hs
@@ -8,7 +8,8 @@
 {-# LANGUAGE TypeFamilies          #-}
 
 module Network.Wai.Routing.Predicate.Content
-    ( ContentType (..)
+    ( ContentType
+    , contentType
     , module Network.Wai.Routing.MediaType
     ) where
 
@@ -28,6 +29,10 @@
 
 -- | A 'Predicate' against the 'Request's \"Content-Type\" header.
 data ContentType (t :: Symbol) (s :: Symbol) = ContentType
+
+contentType :: ContentType t s
+contentType = ContentType
+{-# INLINABLE contentType #-}
 
 type1 :: SingI t => ContentType t s -> ByteString
 type1 m = withSing (f m)
diff --git a/src/Network/Wai/Routing/Predicate/Cookie.hs b/src/Network/Wai/Routing/Predicate/Cookie.hs
--- a/src/Network/Wai/Routing/Predicate/Cookie.hs
+++ b/src/Network/Wai/Routing/Predicate/Cookie.hs
@@ -7,8 +7,10 @@
 {-# LANGUAGE MultiParamTypeClasses #-}
 
 module Network.Wai.Routing.Predicate.Cookie
-    ( Cookie    (..)
-    , HasCookie (..)
+    ( Cookie
+    , HasCookie
+    , cookie
+    , hasCookie
     ) where
 
 import Data.ByteString (ByteString)
@@ -22,6 +24,10 @@
 
 newtype Cookie a = Cookie ByteString
 
+cookie :: ByteString -> Cookie a
+cookie = Cookie
+{-# INLINABLE cookie #-}
+
 instance (FromByteString a) => Predicate (Cookie a) Req where
     type FVal (Cookie a) = Error
     type TVal (Cookie a) = a
@@ -29,6 +35,10 @@
         rqApply (lookupCookie x) readValues (err status400 (msg x))
 
 newtype HasCookie = HasCookie ByteString
+
+hasCookie :: ByteString -> HasCookie
+hasCookie = HasCookie
+{-# INLINABLE hasCookie #-}
 
 instance Predicate HasCookie Req where
     type FVal HasCookie   = Error
diff --git a/src/Network/Wai/Routing/Predicate/Header.hs b/src/Network/Wai/Routing/Predicate/Header.hs
--- a/src/Network/Wai/Routing/Predicate/Header.hs
+++ b/src/Network/Wai/Routing/Predicate/Header.hs
@@ -7,8 +7,10 @@
 {-# LANGUAGE TypeFamilies          #-}
 
 module Network.Wai.Routing.Predicate.Header
-    ( Hdr    (..)
-    , HasHdr (..)
+    ( Hdr
+    , HasHdr
+    , hdr
+    , hasHdr
     ) where
 
 import Data.ByteString (ByteString)
@@ -25,6 +27,10 @@
 
 newtype Hdr a = Hdr ByteString
 
+hdr :: ByteString -> Hdr a
+hdr = Hdr
+{-# INLINABLE hdr #-}
+
 instance (FromByteString a) => Predicate (Hdr a) Req where
     type FVal (Hdr a) = Error
     type TVal (Hdr a) = a
@@ -33,6 +39,10 @@
         rqApply (lookupHeader x) readValues (err status400 msg)
 
 newtype HasHdr = HasHdr ByteString
+
+hasHdr :: ByteString -> HasHdr
+hasHdr = HasHdr
+{-# INLINABLE hasHdr #-}
 
 instance Predicate HasHdr Req where
     type FVal HasHdr   = Error
diff --git a/src/Network/Wai/Routing/Predicate/Param.hs b/src/Network/Wai/Routing/Predicate/Param.hs
--- a/src/Network/Wai/Routing/Predicate/Param.hs
+++ b/src/Network/Wai/Routing/Predicate/Param.hs
@@ -6,8 +6,10 @@
 {-# LANGUAGE MultiParamTypeClasses #-}
 
 module Network.Wai.Routing.Predicate.Param
-    ( Param     (..)
-    , HasParam  (..)
+    ( Param
+    , HasParam
+    , param
+    , hasParam
     ) where
 
 import Data.ByteString (ByteString)
@@ -21,15 +23,23 @@
 -- | @Param \"x\"@ is equivalent to @'Query' \"x\" ':|:' 'Capture' \"x\"@.
 newtype Param a = Param ByteString
 
+param :: ByteString -> Param a
+param = Param
+{-# INLINABLE param #-}
+
 instance (FromByteString a) => Predicate (Param a) Req where
     type FVal (Param a) = Error
     type TVal (Param a) = a
-    apply (Param x)     = apply (Query x :|: Capture x)
+    apply (Param x)     = apply (query x :|: capture x)
 
 newtype HasParam = HasParam ByteString
 
+hasParam :: ByteString -> HasParam
+hasParam = HasParam
+{-# INLINABLE hasParam #-}
+
 instance Predicate HasParam Req where
     type FVal HasParam = Error
     type TVal HasParam = ()
-    apply (HasParam x) = apply (HasQuery x :|: HasCapture x)
+    apply (HasParam x) = apply (hasQuery x :|: hasCapture x)
 
diff --git a/src/Network/Wai/Routing/Predicate/Predicate.hs b/src/Network/Wai/Routing/Predicate/Predicate.hs
--- a/src/Network/Wai/Routing/Predicate/Predicate.hs
+++ b/src/Network/Wai/Routing/Predicate/Predicate.hs
@@ -8,8 +8,34 @@
 {-# LANGUAGE TypeFamilies          #-}
 {-# LANGUAGE TypeOperators         #-}
 
-module Network.Wai.Routing.Predicate.Predicate where
+module Network.Wai.Routing.Predicate.Predicate
+    ( Delta
+    , Boolean   (..)
+    , Predicate (..)
+    , (:|:)     (..)
+    , (:&:)     (..)
+    , (:||:)    (..)
+    , (:::)     (..)
+    , (:+:)
+    , Const
+    , Fail
+    , Opt
+    , Def
+    , PMap
+    , PMapT
+    , PMapF
 
+    , constant
+    , failure
+    , true
+    , opt
+    , def
+    , pmap
+    , pmapT
+    , pmapF
+    , with
+    ) where
+
 import Prelude hiding (and, or)
 
 -- | 'Delta' is a measure of distance. It is (optionally)
@@ -53,14 +79,23 @@
     type TVal (Const f t) = t
     apply (Const a) _     = T 0 a
 
+constant :: t -> Const f t
+constant = Const
+{-# INLINABLE constant #-}
+
 true :: Const a ()
 true = Const ()
+{-# INLINABLE true #-}
 
 -- | A 'Predicate' instance which always returns 'F' with
 -- the given value as F's meta-data.
 data Fail f t where
     Fail :: f -> Fail f t
 
+failure :: f -> Fail f t
+failure = Fail
+{-# INLINABLE failure #-}
+
 instance Predicate (Fail f t) a where
     type FVal (Fail f t) = f
     type TVal (Fail f t) = t
@@ -125,11 +160,15 @@
         and (T _ _) (F   f) = F f
         and (F   f) _       = F f
 
--- | An 'Predicate' modifier which makes the underlying predicate optional,
+-- | A 'Predicate' modifier which makes the underlying predicate optional,
 -- i.e. the 'TVal' becomes a 'Maybe' and in the failure-case 'Nothing' is
 -- returned.
 newtype Opt a = Opt a
 
+opt :: a -> Opt a
+opt = Opt
+{-# INLINABLE opt #-}
+
 instance (Predicate a b) => Predicate (Opt a) b where
     type FVal (Opt a) = FVal a
     type TVal (Opt a) = Maybe (TVal a)
@@ -137,16 +176,61 @@
         T d x -> T d (Just x)
         F _   -> T 0 Nothing
 
--- | An 'Predicate' modifier which returns as 'TVal' the provided default
+-- | A 'Predicate' modifier which returns as 'TVal' the provided default
 -- value if the underlying predicate fails.
 data Def d a = Def d a
 
+def :: d -> a -> Def d a
+def = Def
+{-# INLINABLE def #-}
+
 instance (Predicate a b, d ~ TVal a) => Predicate (Def d a) b where
     type FVal (Def d a) = FVal a
     type TVal (Def d a) = TVal a
     apply (Def d a) r   = case apply a r of
         T n x -> T n x
         F _   -> T 0 d
+
+-- | A 'Predicate' function, i.e. a function of the underlying predicate's
+-- result.
+data PMap a f t = PMap (Boolean (FVal a) (TVal a) -> Boolean f t) a
+
+pmap :: (Boolean (FVal a) (TVal a) -> Boolean f t) -> a -> PMap a f t
+pmap = PMap
+{-# INLINABLE pmap #-}
+
+instance (Predicate a b) => Predicate (PMap a f t) b where
+    type FVal (PMap a f t) = f
+    type TVal (PMap a f t) = t
+    apply (PMap f a) r     = f $ apply a r
+
+-- | Like 'PMap' but a function of the underlying predicate's 'TVal'.
+data PMapT a t = PMapT (TVal a -> Boolean (FVal a) t) a
+
+pmapT :: (TVal a -> Boolean (FVal a) t) -> a -> PMapT a t
+pmapT = PMapT
+{-# INLINABLE pmapT #-}
+
+instance (Predicate a b) => Predicate (PMapT a t) b where
+    type FVal (PMapT a t) = FVal a
+    type TVal (PMapT a t) = t
+    apply (PMapT f a) r   = case apply a r of
+        (T _ x) -> f x
+        (F x)   -> F x
+
+-- | Like 'PMap' but a function of the underlying predicate's 'FVal'.
+data PMapF a f = PMapF (FVal a -> Boolean f (TVal a)) a
+
+pmapF :: (FVal a -> Boolean f (TVal a)) -> a -> PMapF a f
+pmapF = PMapF
+{-# INLINABLE pmapF #-}
+
+instance (Predicate a b) => Predicate (PMapF a f) b where
+    type FVal (PMapF a f) = f
+    type TVal (PMapF a f) = TVal a
+    apply (PMapF f a) r   = case apply a r of
+        (F   x) -> f x
+        (T d x) -> T d x
 
 -- | The 'with' function will invoke the given function only if the predicate 'p'
 -- applied to the test value 'a' evaluates to 'T'.
diff --git a/src/Network/Wai/Routing/Predicate/Query.hs b/src/Network/Wai/Routing/Predicate/Query.hs
--- a/src/Network/Wai/Routing/Predicate/Query.hs
+++ b/src/Network/Wai/Routing/Predicate/Query.hs
@@ -7,8 +7,10 @@
 {-# LANGUAGE MultiParamTypeClasses #-}
 
 module Network.Wai.Routing.Predicate.Query
-    ( Query    (..)
-    , HasQuery (..)
+    ( Query
+    , HasQuery
+    , query
+    , hasQuery
     ) where
 
 import Data.ByteString (ByteString)
@@ -22,6 +24,10 @@
 
 newtype Query a = Query ByteString
 
+query :: ByteString -> Query a
+query = Query
+{-# INLINABLE query #-}
+
 instance (FromByteString a) => Predicate (Query a) Req where
     type FVal (Query a) = Error
     type TVal (Query a) = a
@@ -30,6 +36,10 @@
         rqApply (lookupQuery x) readValues (err status400 msg)
 
 newtype HasQuery = HasQuery ByteString
+
+hasQuery :: ByteString -> HasQuery
+hasQuery = HasQuery
+{-# INLINABLE hasQuery #-}
 
 instance Predicate HasQuery Req where
     type FVal HasQuery   = Error
diff --git a/src/Network/Wai/Routing/Route.hs b/src/Network/Wai/Routing/Route.hs
--- a/src/Network/Wai/Routing/Route.hs
+++ b/src/Network/Wai/Routing/Route.hs
@@ -2,7 +2,6 @@
 -- License, v. 2.0. If a copy of the MPL was not distributed with this
 -- file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-{-# LANGUAGE BangPatterns      #-}
 {-# LANGUAGE GADTs             #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE TypeOperators     #-}
@@ -12,7 +11,7 @@
     ( Routes
     , Renderer
     , route
-    , expand
+    , prepare
     , renderer
     , addRoute
     , get
@@ -23,6 +22,8 @@
     , trace
     , options
     , connect
+    , attach
+    , examine
     ) where
 
 import Control.Applicative hiding (Const)
@@ -33,7 +34,7 @@
 import Data.Either
 import Data.Function
 import Data.List hiding (head, delete)
-import Data.Maybe (fromMaybe)
+import Data.Maybe (fromMaybe, mapMaybe)
 import Data.Monoid
 import Network.HTTP.Types
 import Network.Wai (Request, Response, responseLBS, responseBuilder, rawPathInfo)
@@ -46,9 +47,10 @@
 import qualified Data.List              as L
 import qualified Network.Wai.Route.Tree as Tree
 
-data Route m = Route
+data Route a m = Route
     { _method  :: !Method
     , _path    :: !ByteString
+    , _meta    :: Maybe a
     , _pred    :: Pack m
     }
 
@@ -69,28 +71,31 @@
 
 -- | Set a custom render function, i.e. a function to turn 'Error's into
 -- 'Lazy.ByteString's.
-renderer :: Renderer -> Routes m ()
-renderer f = Routes . modify $ \(St !rr _) -> St rr f
+renderer :: Renderer -> Routes m a ()
+renderer f = Routes . modify $ \s -> s { renderfn = f }
 
 -- | The Routes monad state type.
-data St m = St [Route m] Renderer
+data St a m = St
+    { routes   :: [Route a m]
+    , renderfn :: Renderer
+    }
 
 -- | Initial state.
-zero :: St m
+zero :: St a m
 zero = St [] (fmap Lazy.fromStrict . message)
 
 -- | The Routes monad is used to add routing declarations
 -- via 'addRoute' or one of 'get', 'post', etc.
-newtype Routes m a = Routes { _unroutes :: State (St m) a }
+newtype Routes a m b = Routes { _unroutes :: State (St a m) b }
 
-instance Functor (Routes m) where
+instance Functor (Routes a m) where
     fmap = liftM
 
-instance Applicative (Routes m) where
+instance Applicative (Routes a m) where
     pure  = return
     (<*>) = ap
 
-instance Monad (Routes m) where
+instance Monad (Routes a m) where
     return  = Routes . return
     m >>= f = Routes $ _unroutes m >>= _unroutes . f
 
@@ -101,9 +106,9 @@
          -> ByteString             -- ^ path
          -> (TVal p -> m Response) -- ^ handler
          -> p                      -- ^ 'Predicate'
-         -> Routes m ()
-addRoute m r x p = Routes . modify $ \(St !rr !f) ->
-    St (Route m r (Pack p x) : rr) f
+         -> Routes a m ()
+addRoute m r x p = Routes . modify $ \s ->
+    s { routes = Route m r Nothing (Pack p x) : routes s }
 
 -- | Specialisation of 'addRoute' for a specific HTTP 'Method'.
 get, head, post, put, delete, trace, options, connect ::
@@ -111,7 +116,7 @@
     => ByteString             -- ^ path
     -> (TVal p -> m Response) -- ^ handler
     -> p                      -- ^ 'Predicate'
-    -> Routes m ()
+    -> Routes a m ()
 get     = addRoute (renderStdMethod GET)
 head    = addRoute (renderStdMethod HEAD)
 post    = addRoute (renderStdMethod POST)
@@ -121,11 +126,23 @@
 options = addRoute (renderStdMethod OPTIONS)
 connect = addRoute (renderStdMethod CONNECT)
 
+-- | Add some metadata to the last route.
+attach :: a -> Routes a m ()
+attach a = Routes $ modify addToLast
+  where
+    addToLast s@(St []   _) = s
+    addToLast (St (r:rr) f) = St (r { _meta = Just a } : rr) f
+
+-- | Get back all attached metadata.
+examine :: Routes a m b -> [a]
+examine (Routes r) = let St rr _ = execState r zero in
+    mapMaybe _meta rr
+
 -- | A WAI 'Application' (generalised from 'IO' to 'Monad') which
 -- routes requests to handlers based on predicated route declarations.
-route :: Monad m => Routes m a -> Request -> m Response
+route :: Monad m => [(ByteString, Req -> m Response)] -> Request -> m Response
 route rm rq = do
-    let tr = Tree.fromList $ expand rm
+    let tr = Tree.fromList rm
     case Tree.lookup tr (Tree.segments $ rawPathInfo rq) of
         Just (f, v) -> f (fromWaiRequest v rq)
         Nothing     -> return notFound
@@ -133,26 +150,26 @@
     notFound = responseLBS status404 [] ""
 
 -- | Run the 'Routes' monad and return the handlers per path.
-expand :: Monad m => Routes m a -> [(ByteString, Req -> m Response)]
-expand (Routes routes) =
-    let St rr f = execState routes zero in
-    map (\g -> (_path (L.head g), select f g)) (normalise rr)
+prepare :: Monad m => Routes a m b -> [(ByteString, Req -> m Response)]
+prepare (Routes rr) =
+    let s = execState rr zero in
+    map (\g -> (_path (L.head g), select (renderfn s) g)) (normalise (routes s))
 
 -- | Group routes by path.
-normalise :: [Route m] -> [[Route m]]
+normalise :: [Route a m] -> [[Route a m]]
 normalise rr =
     let rg    = grouped . sorted $ rr
         paths = map (namelessPath . L.head) rg
         ambig = paths \\ nub paths
     in if null ambig then rg else error (ambiguityMessage ambig)
   where
-    sorted :: [Route m] -> [Route m]
+    sorted :: [Route a m] -> [Route a m]
     sorted = sortBy (compare `on` _path)
 
-    grouped :: [Route m] -> [[Route m]]
+    grouped :: [Route a m] -> [[Route a m]]
     grouped = groupBy ((==) `on` _path)
 
-    namelessPath :: Route m -> ByteString
+    namelessPath :: Route a m -> ByteString
     namelessPath =
         let fun s = if s /= "" && C.head s == ':' then "<>" else s
         in C.intercalate "/" . map fun . C.split '/' . _path
@@ -167,9 +184,9 @@
 -- (2) Evaluate 'Route' predicates.
 -- (3) Pick the first one which is 'Good', or else respond with status
 --     and message of the first one.
-select :: Monad m => Renderer -> [Route m] -> Req -> m Response
-select render routes req = do
-    let ms = filter ((method req ==) . _method) routes
+select :: Monad m => Renderer -> [Route a m] -> Req -> m Response
+select render rr req = do
+    let ms = filter ((method req ==) . _method) rr
     if null ms
         then return $ respond render (Error status405 Nothing) [(allow, validMethods)]
         else evalAll ms
@@ -178,16 +195,16 @@
     allow = mk "Allow"
 
     validMethods :: ByteString
-    validMethods = C.intercalate "," $ nub (C.pack . show . _method <$> routes)
+    validMethods = C.intercalate "," $ nub (C.pack . show . _method <$> rr)
 
-    evalAll :: Monad m => [Route m] -> m Response
+    evalAll :: Monad m => [Route a m] -> m Response
     evalAll rs =
         let (n, y) = partitionEithers $ foldl' evalSingle [] rs
         in if null y
             then return $ respond render (L.head n) []
             else closest y
 
-    evalSingle :: Monad m => [Either Error (Handler m)] -> Route m -> [Either Error (Handler m)]
+    evalSingle :: Monad m => [Either Error (Handler m)] -> Route a m -> [Either Error (Handler m)]
     evalSingle rs r =
         case _pred r of
             Pack p h -> case apply p req of
diff --git a/src/Network/Wai/Routing/Tutorial.hs b/src/Network/Wai/Routing/Tutorial.hs
--- a/src/Network/Wai/Routing/Tutorial.hs
+++ b/src/Network/Wai/Routing/Tutorial.hs
@@ -132,7 +132,7 @@
 @
 someHandler :: Application
 someHandler r =
-    case apply (Accept :&: Query \"baz\") (fromWaiRequest [] r) of
+    case apply (accept :&: query \"baz\") (fromWaiRequest [] r) of
         T ((_ :: Media \"text\" \"plain\") ::: bazValue) -> ...
         F (Just (Error st msg))                      -> ...
         F Nothing                                    -> ...
@@ -149,11 +149,11 @@
 @
 sitemap :: Routes ()
 sitemap = do
-    get  \"\/a\" handlerA $ Accept :&: (Query \"name\" :|: Query \"nick\") :&: Query \"foo\"
-    get  \"\/b\" handlerB $ Accept :&: (Query \"name\" :||: Query \"nick\") :&: Query \"foo\"
-    get  \"\/c\" handlerC $ Fail (Error 410 (Just \"Gone.\"))
-    post \"\/d\" handlerD $ Accept
-    post \"\/e\" handlerE $ Accept
+    get  \"\/a\" handlerA $ accept :&: (query \"name\" :|: query \"nick\") :&: query \"foo\"
+    get  \"\/b\" handlerB $ accept :&: (query \"name\" :||: query \"nick\") :&: query \"foo\"
+    get  \"\/c\" handlerC $ failure (Error 410 (Just \"Gone.\"))
+    post \"\/d\" handlerD $ accept
+    post \"\/e\" handlerE $ accept
 @
 
 Handler definitions encode their pre-conditions in their type-signature:
diff --git a/test/Tests/Wai/Predicate.hs b/test/Tests/Wai/Predicate.hs
--- a/test/Tests/Wai/Predicate.hs
+++ b/test/Tests/Wai/Predicate.hs
@@ -26,51 +26,51 @@
 testAcceptJson :: IO ()
 testAcceptJson = do
     let rq0 = fromWaiRequest [] . json $ request "/"
-    (T 0 $ Media "application" "json" 1.0 []) @=? (apply (Accept :: Accept "application" "json") rq0)
+    T 0 (Media "application" "json" 1.0 []) @=? apply (accept :: Accept "application" "json") rq0
 
     let rq1 = fromWaiRequest [] . withHeader "Accept" "foo/bar" $ request "/"
-    (F (err status406 ("Expected 'Accept: application/json'."))) @=? (apply (Accept :: Accept "application" "json") rq1)
+    F (err status406 ("Expected 'Accept: application/json'.")) @=? apply (accept :: Accept "application" "json") rq1
 
 testAcceptThrift :: IO ()
 testAcceptThrift = do
     let rq0 = fromWaiRequest [] . withHeader "Accept" "application/x-thrift" $ request "/"
-    (T 0 $ Media "application" "x-thrift" 1.0 []) @=? (apply (Accept :: Accept "application" "x-thrift") rq0)
+    T 0 (Media "application" "x-thrift" 1.0 []) @=? apply (accept :: Accept "application" "x-thrift") rq0
 
     let rq1 = fromWaiRequest [] . json $ request "/"
-    (F (err status406 ("Expected 'Accept: application/x-thrift'."))) @=? (apply (Accept :: Accept "application" "x-thrift") rq1)
+    F (err status406 ("Expected 'Accept: application/x-thrift'.")) @=? apply (accept :: Accept "application" "x-thrift") rq1
 
 testAcceptAll :: IO ()
 testAcceptAll = do
     let rq0 = fromWaiRequest [] . withHeader "Accept" "application/*" $ request "/"
-    (T 0 $ Media "application" "*"    1.0 []) @=? apply (Accept :: Accept "application" "*") rq0
-    (T 0 $ Media "application" "json" 1.0 []) @=? apply (Accept :: Accept "application" "json") rq0
+    T 0 (Media "application" "*"    1.0 []) @=? apply (accept :: Accept "application" "*") rq0
+    T 0 (Media "application" "json" 1.0 []) @=? apply (accept :: Accept "application" "json") rq0
 
 testContentTypePlain :: IO ()
 testContentTypePlain = do
     let rq0 = fromWaiRequest [] . withHeader "Content-Type" "text/plain" $ request "/"
-    (T 0 $ Media "text" "plain" 1.0 []) @=? (apply (ContentType :: ContentType "text" "plain") rq0)
+    T 0 (Media "text" "plain" 1.0 []) @=? apply (contentType :: ContentType "text" "plain") rq0
 
     let rq1 = fromWaiRequest [] . withHeader "Content-Type" "text/html" $ request "/"
-    (F (err status415 ("Expected 'Content-Type: text/plain'."))) @=? (apply (ContentType :: ContentType "text" "plain") rq1)
+    F (err status415 ("Expected 'Content-Type: text/plain'.")) @=? apply (contentType :: ContentType "text" "plain") rq1
 
 testContentTypeAll :: IO ()
 testContentTypeAll = do
     let rq0 = fromWaiRequest [] . withHeader "Content-Type" "text/plain" $ request "/"
-    (T 0.5 $ Media "text" "plain" 0.5 []) @=? (apply (ContentType :: ContentType "text" "*") rq0)
+    T 0.5 (Media "text" "plain" 0.5 []) @=? apply (contentType :: ContentType "text" "*") rq0
 
 testQuery :: IO ()
 testQuery = do
     let rq0 = fromWaiRequest [] . withQuery "x" "y" . withQuery "x" "z" $ request "/"
-    (T 0 "y") @=? (apply (Query "x" :: Query ByteString) rq0)
+    T 0 "y" @=? apply (query "x" :: Query ByteString) rq0
 
     let rq1 = fromWaiRequest [] $ request "/"
-    (F (err status400 ("Missing query 'x'."))) @=? (apply (Query "x" :: Query ByteString) rq1)
+    F (err status400 ("Missing query 'x'.")) @=? apply (query "x" :: Query ByteString) rq1
 
 testQueryOpt :: IO ()
 testQueryOpt = do
     let rq0 = fromWaiRequest [] . withQuery "x" "y" . withQuery "x" "z" $ request "/"
-    (T 0 (Just "y")) @=? (apply (Opt (Query "x" :: Query ByteString)) rq0)
+    T 0 (Just "y") @=? apply (opt (query "x" :: Query ByteString)) rq0
 
     let rq1 = fromWaiRequest [] $ request "/"
-    (T 0 Nothing) @=? (apply (Opt (Query "x" :: Query ByteString)) rq1)
+    T 0 Nothing @=? apply (opt (query "x" :: Query ByteString)) rq1
 
diff --git a/test/Tests/Wai/Route.hs b/test/Tests/Wai/Route.hs
--- a/test/Tests/Wai/Route.hs
+++ b/test/Tests/Wai/Route.hs
@@ -25,12 +25,12 @@
 
 testSitemap :: IO ()
 testSitemap = do
-    let routes  = expand sitemap
-    assertEqual "Endpoints"
-        ["/a", "/b", "/c", "/d", "/e", "/f", "/g", "/h"]
-        (map fst routes)
+    let routes = prepare sitemap
 
-    let handler = route sitemap
+    [7,6,5,4,3,2,1,0] @=? examine sitemap
+    ["/a", "/b", "/c", "/d", "/e", "/f", "/g", "/h"] @=? map fst routes
+
+    let handler = route routes
     testEndpointA handler
     testEndpointB handler
     testEndpointC handler
@@ -39,31 +39,47 @@
     testEndpointF handler
     testEndpointH handler
 
-sitemap :: Routes IO ()
+sitemap :: Routes Int IO ()
 sitemap = do
     get "/a" handlerA $
-        Accept :&: (Query "name" :|: Query "nick") :&: Query "foo"
+        accept :&: (query "name" :|: query "nick") :&: query "foo"
 
+    attach 0
+
     get "/b" handlerB $
-        Query "baz"
+        query "baz"
 
+    attach 1
+
     get "/c" handlerC $
-        Opt (Query "foo")
+        opt (query "foo")
 
+    attach 2
+
     get "/d" handlerD $
-        Def 0 (Query "foo")
+        def 0 (query "foo")
 
+    attach 3
+
     get "/e" handlerE $
-        Def 0 (Hdr "foo")
+        def 0 (hdr "foo")
 
+    attach 4
+
     get "/f" handlerF $
-        Query "foo"
+        query "foo"
 
+    attach 5
+
     get "/g" handlerG true
 
+    attach 6
+
     get "/h" handlerH $
-        Cookie "user" :&: Cookie "age"
+        cookie "user" :&: cookie "age"
 
+    attach 7
+
 handlerA :: Media "application" "json" ::: Int ::: ByteString -> IO Response
 handlerA (_ ::: i ::: _) = writeText (fromString . show $ i)
 
@@ -203,14 +219,14 @@
 
 testMedia :: IO ()
 testMedia = do
-    let [(_, h)] = expand sitemapMedia
+    let [(_, h)] = prepare sitemapMedia
     expectMedia "application/json;q=0.3, application/x-thrift;q=0.7" "application/x-thrift" h
     expectMedia "application/json;q=0.7, application/x-thrift;q=0.3" "application/json" h
 
-sitemapMedia :: Routes IO ()
+sitemapMedia :: Routes a IO ()
 sitemapMedia = do
-    get "/media" handlerJson   Accept
-    get "/media" handlerThrift Accept
+    get "/media" handlerJson   accept
+    get "/media" handlerThrift accept
 
 handlerJson :: Media "application" "json" -> IO Response
 handlerJson _ = writeText "application/json"
diff --git a/wai-routing.cabal b/wai-routing.cabal
--- a/wai-routing.cabal
+++ b/wai-routing.cabal
@@ -1,5 +1,5 @@
 name:                wai-routing
-version:             0.1
+version:             0.2
 synopsis:            Declarative routing for WAI.
 license:             OtherLicense
 license-file:        LICENSE
