diff --git a/rtree/rtree.cabal b/rtree/rtree.cabal
index 2b35f24639aaead895311655d5ec8b49d18528e1..7070af5902458ae4e86143fb5c699dacd7591d33 100644
--- a/rtree/rtree.cabal
+++ b/rtree/rtree.cabal
@@ -10,9 +10,11 @@ build-type:     Simple
 
 library
   exposed-modules:
+      Control.Monad.IRTree
       Control.Monad.Reduce
       Control.Monad.RTree
       Control.RTree
+      Data.RPath
       Data.Valuation
   other-modules:
       Paths_rtree
@@ -33,7 +35,9 @@ test-suite rtree-test
   type: exitcode-stdio-1.0
   main-is: Main.hs
   other-modules:
+      Control.Monad.IRTreeSpec
       Control.Monad.RTreeSpec
+      Data.Expr
       Spec
       Test.Hspec.GitGolden
       Paths_rtree
diff --git a/rtree/src/Control/Monad/IRTree.hs b/rtree/src/Control/Monad/IRTree.hs
new file mode 100644
index 0000000000000000000000000000000000000000..7694e77ad0b8ad782d1d53d396a9f0050b818b41
--- /dev/null
+++ b/rtree/src/Control/Monad/IRTree.hs
@@ -0,0 +1,121 @@
+{-# LANGUAGE BlockArguments #-}
+{-# LANGUAGE DerivingVia #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RankNTypes #-}
+
+module Control.Monad.IRTree (
+  -- * IRTree
+  IRTree,
+  extract,
+  reduce,
+  reduceExp,
+
+  -- * IRTreeT
+  IRTreeT,
+  extractT,
+  reduceT,
+  reduceExpT,
+
+  -- * Re-exports
+  module Control.Monad.Reader,
+  module Data.RPath,
+) where
+
+import Control.Monad.Reader
+import Control.Monad.Reduce
+import Control.Monad.State
+import Data.Bits
+import Data.Foldable
+import Data.Functor.Identity
+import Data.RPath
+import qualified Data.Sequence as Seq
+
+type IRTree = IRTreeT Identity
+
+newtype IRTreeT m i = IRTreeT (RPath -> Int -> m (i, Int))
+  deriving
+    (Functor, Applicative, Monad)
+    via (ReaderT RPath (StateT Int m))
+
+instance (Monad m) => MonadReduce (IRTreeT m) where
+  check = IRTreeT \rp i -> do
+    pure (indexChoice rp i, i + 1)
+
+extract :: IRTree i -> i
+extract t = runIdentity $ extractT t
+{-# INLINE extract #-}
+
+extractT :: (Functor m) => IRTreeT m i -> m i
+extractT (IRTreeT m) = fmap fst (m "" 0)
+{-# INLINE extractT #-}
+
+reduce
+  :: (Monad m)
+  => (i -> m Bool)
+  -> IRTree i
+  -> m (Maybe i)
+reduce = reduceT (pure . runIdentity)
+{-# INLINE reduce #-}
+
+-- | Interpreted reduction with an m base monad
+reduceT
+  :: (Monad m)
+  => (forall a. t a -> m a)
+  -> (i -> m Bool)
+  -> IRTreeT t i
+  -> m (Maybe i)
+reduceT lift_ p (IRTreeT m) = do
+  (i, _) <- lift_ (m "" 0)
+  t <- p i
+  if t
+    then Just <$> go Seq.empty
+    else pure Nothing
+ where
+  go pth = do
+    -- Try to run the true branch.
+    let pth' = fromChoiceList (toList (pth Seq.|> True))
+    (i, x) <- lift_ (m pth' 0)
+    t <- p i
+    if x >= numberOfChoices pth'
+      then go (pth Seq.|> t)
+      else pure i
+{-# INLINE reduceT #-}
+
+reduceExp
+  :: (Monad m)
+  => (i -> m Bool)
+  -> IRTree i
+  -> m (Maybe i)
+reduceExp = reduceExpT (pure . runIdentity)
+{-# INLINE reduceExp #-}
+
+-- | Interpreted reduction with an m base monad, and running in expoential mode.
+reduceExpT
+  :: (Monad m)
+  => (forall a. t a -> m a)
+  -- ^ a lift of monad m into t (normally @id@ or @lift@)
+  -> (i -> m Bool)
+  -> IRTreeT t i
+  -> m (Maybe i)
+reduceExpT lift_ p (IRTreeT m) = do
+  (i, _) <- lift_ (m "" 0)
+  t <- p i
+  if t
+    then Just <$> go 0 Seq.empty
+    else pure Nothing
+ where
+  go n sq = do
+    let depth = shiftL 1 n
+    let sq' = sq <> Seq.replicate depth True
+    let pth' = fromChoiceList (toList sq')
+    (i, x) <- lift_ (m pth' 0)
+    t <- p i
+    if x >= numberOfChoices pth' - depth + 1
+      then
+        if t
+          then go (n + 1) sq'
+          else case n of
+            0 -> go 0 (sq Seq.|> False)
+            n' -> go (n' - 1) sq
+      else pure i
+{-# INLINE reduceExpT #-}
diff --git a/rtree/src/Control/RTree.hs b/rtree/src/Control/RTree.hs
deleted file mode 100644
index 7290fb616a957b2ec314454845cea04039b53c7f..0000000000000000000000000000000000000000
--- a/rtree/src/Control/RTree.hs
+++ /dev/null
@@ -1,234 +0,0 @@
-{-# LANGUAGE BlockArguments #-}
-{-# LANGUAGE DeriveFunctor #-}
-{-# LANGUAGE DerivingVia #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE KindSignatures #-}
-{-# LANGUAGE LambdaCase #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE RankNTypes #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE UndecidableInstances #-}
-{-# LANGUAGE ViewPatterns #-}
-
-{- |
-Module: Control.RTree
--}
-module Control.RTree (
--- -- # RTree
--- RTree (..),
--- extract,
--- reduce,
--- reduceMaybe,
--- -- # IRTree
--- IRTree,
--- iextract,
--- ireduce,
--- ireduceExp,
--- IRTreeT (..),
--- iextractT,
--- ireduceT,
--- ireduceExpT,
--- ReState (..),
--- -- # Valuation
--- Valuation,
-
-) where
-
--- import Control.Applicative
--- import Control.Monad.Reader
--- import Control.Monad.State.Strict
--- import Data.Functor.Identity
---
--- import qualified Data.Vector as V
---
--- import Control.Monad.Reduce
--- import Control.Monad.Trans.Maybe
--- import Data.Bits
--- import Data.Maybe
--- import qualified Data.Valuation as Val
---
--- type Valuation = Val.Valuation
--- type Truth = Val.Truth
---
--- data RTree l i
---   = Bottom
---   | Done i
---   | SplitWith (Maybe (Truth l)) (RTree l i) !(RTree l i)
---   deriving (Functor)
---
--- extract :: (Ord l) => Valuation l -> RTree l i -> Maybe i
--- extract v = \case
---   Bottom -> Nothing
---   SplitWith ml lhs rhs -> case ml >>= Val.condition v of
---     Just v' -> extract v' rhs
---     _ -> extract v lhs
---   Done i -> Just i
---
--- instance Applicative (RTree l) where
---   pure = Done
---   (<*>) = ap
---
--- instance Monad (RTree l) where
---   ma >>= f = case ma of
---     Bottom -> Bottom
---     Done i -> f i
---     SplitWith ml lhs rhs -> SplitWith ml (lhs >>= f) (rhs >>= f)
---
--- instance MonadReduce l (RTree l) where
---   splitWith = SplitWith
---   bottom = Bottom
---
--- reduce
---   :: forall m l i
---    . (Alternative m, Ord l)
---   => (Valuation l -> i -> m ())
---   -> Valuation l
---   -> RTree l i
---   -> m i
--- reduce p = checkgo
---  where
---   checkgo v r =
---     case extract v r of
---       Nothing -> empty
---       Just e -> p v e *> go v r
---   go v = \case
---     Bottom -> empty
---     Done i -> pure i
---     SplitWith (Just l) lhs rhs -> case Val.truthValue v (Val.label l) of
---       Just t
---         | t == Val.truth l -> checkgo v rhs
---         | otherwise -> checkgo v lhs
---       Nothing -> checkgo (Val.withTruth v $ Val.not l) lhs <|> go (Val.withTruth v l) rhs
---     SplitWith Nothing lhs rhs -> (checkgo v lhs <|> go v rhs)
--- {-# INLINE reduce #-}
---
--- reduceMaybe
---   :: forall m l i
---    . (Monad m, Ord l)
---   => (Valuation l -> i -> m Bool)
---   -> Valuation l
---   -> RTree l i
---   -> m (Maybe i)
--- reduceMaybe p v rt =
---   runMaybeT
---     $ reduce
---       ( \v' i -> do
---           t <- lift (p v' i)
---           unless t empty
---       )
---       v
---       rt
---
--- data ReState l = ReState
---   { choices :: V.Vector Bool
---   , progress :: Int
---   , valuation :: !(Valuation l)
---   }
---
--- type IRTree l = IRTreeT l Identity
---
--- newtype IRTreeT l m i = IRTreeT {runIRTreeT :: MaybeT (StateT (ReState l) m) i}
---   deriving (Functor, Applicative, Alternative, Monad, MonadPlus) via (MaybeT (StateT (ReState l) m))
---
--- instance MonadTrans (IRTreeT l) where
---   lift m = IRTreeT (lift (lift m))
---
--- instance (MonadState s m) => MonadState s (IRTreeT l m) where
---   state s = lift (state s)
---
--- instance (Monad m, Ord l) => MonadReduce l (IRTreeT l m) where
---   bottom = mzero
---   checkWith =
---     IRTreeT . MaybeT . StateT . \case
---       Nothing -> \case
---         ReState ch i v ->
---           pure (Just (fromMaybe True (ch V.!? i)), ReState ch (i + 1) v)
---       Just l -> \case
---         ReState ch i v@((`Val.truthValue` Val.label l) -> Just t) ->
---           pure (Just (t == Val.truth l), ReState ch i v)
---         ReState ch i v ->
---           let a = fromMaybe True (ch V.!? i)
---            in pure (Just a, ReState ch (i + 1) (Val.withTruth v (if a then l else Val.not l)))
---   {-# INLINE checkWith #-}
---
--- iextract :: (Ord l) => Valuation l -> IRTree l a -> Maybe a
--- iextract v t = runIdentity $ iextractT v t
--- {-# INLINE iextract #-}
---
--- iextractT :: (Ord l, Monad m) => Valuation l -> IRTreeT l m i -> m (Maybe i)
--- iextractT v (IRTreeT m) = evalStateT (runMaybeT m) (ReState V.empty 0 v)
--- {-# INLINE iextractT #-}
---
--- ireduce
---   :: forall m l i
---    . (Monad m, Ord l)
---   => (ReState l -> Maybe i -> m Bool)
---   -> Valuation l
---   -> IRTree l i
---   -> m (Maybe i)
--- ireduce = ireduceT (pure . runIdentity)
--- {-# INLINE ireduce #-}
---
--- -- | Interpreted reduction with an m base monad
--- ireduceT
---   :: forall t m l i
---    . (Monad m, Monad t, Ord l)
---   => (forall a. m a -> t a)
---   -- ^ a lift of monad m into t (normally @id@ or @lift@)
---   -> (ReState l -> Maybe i -> t Bool)
---   -> Valuation l
---   -> IRTreeT l m i
---   -> t (Maybe i)
--- ireduceT lift_ p v (IRTreeT m) = go V.empty
---  where
---   go pth = do
---     -- Try to run the false branch.
---     let pth' = pth <> V.singleton False
---     result <- lift_ (runStateT (runMaybeT m) (ReState pth' 0 v))
---     case result of
---       (mi, ReState _ i v') | i >= V.length pth' -> do
---         t <- p (ReState pth' i v') mi
---         -- if the predicate is true, we can reduce to the false branch.
---         go (pth <> V.singleton (not t))
---
---       -- if we no more choices are needed, stop.
---       (mi, _) -> pure mi
--- {-# INLINE ireduceT #-}
---
--- ireduceExp
---   :: forall m l i
---    . (Monad m, Ord l)
---   => (ReState l -> Maybe i -> m Bool)
---   -> Valuation l
---   -> IRTree l i
---   -> m (Maybe i)
--- ireduceExp = ireduceExpT (pure . runIdentity)
--- {-# INLINE ireduceExp #-}
---
--- -- | Interpreted reduction with an m base monad, and running in expoential mode.
--- ireduceExpT
---   :: forall t m l i
---    . (Monad m, Monad t, Ord l)
---   => (forall a. m a -> t a)
---   -- ^ a lift of monad m into t (normally @id@ or @lift@)
---   -> (ReState l -> Maybe i -> t Bool)
---   -> Valuation l
---   -> IRTreeT l m i
---   -> t (Maybe i)
--- ireduceExpT lift_ p v (IRTreeT m) = go 0 V.empty
---  where
---   -- here n is the number of explorative elements
---   go n pth = do
---     let depth = shiftL 1 n
---     let pth' = pth <> V.replicate depth False
---     result <- lift_ (runStateT (runMaybeT m) $ ReState pth' 0 v)
---     case result of
---       (mi, ReState _ i v') | i >= length pth' - depth + 1 -> do
---         t <- p (ReState pth' i v') mi
---         if t
---           then go (n + 1) pth'
---           else case n of
---             0 -> go 0 (pth <> V.singleton True)
---             n' -> go (n' - 1) pth
---       (mi, _) -> pure mi
diff --git a/rtree/src/Data/RPath.hs b/rtree/src/Data/RPath.hs
index 9d8bf616057444bceebbf86f8a5a64d4449c61c5..df436f52e71d50e6bcc5e1de25790828ceb0e87d 100644
--- a/rtree/src/Data/RPath.hs
+++ b/rtree/src/Data/RPath.hs
@@ -3,10 +3,15 @@ module Data.RPath (
   RPath,
   fromChoiceList,
   toChoiceList,
+  numberOfChoices,
+  indexChoice,
 
   -- * As a predicate
   toPredicate,
   toPredicateDebug,
+
+  -- * Helpers
+  debugShowWithDepth,
 ) where
 
 import Data.Bool
@@ -22,19 +27,32 @@ newtype RPath = RPath {rPathAsVector :: VU.Vector Bool}
   deriving (Eq, Ord)
 
 toPredicate :: RPath -> IO (i -> IO Bool)
-toPredicate (RPath v) = do
+toPredicate rp = do
   idx <- newIORef (-1)
   pure . const $ do
     idx' <- atomicModifyIORef idx (\n -> (n + 1, n))
-    pure (fromMaybe True (v VU.!? idx'))
+    pure $ indexChoice rp idx'
 
 toPredicateDebug :: (Show i) => RPath -> IO (i -> IO Bool)
-toPredicateDebug rp@(RPath v) = do
+toPredicateDebug rp = do
   idx <- newIORef (-1)
   pure $ \i -> do
     idx' <- atomicModifyIORef idx (\n -> (n + 1, n))
-    print (rp, idx', i)
-    pure (fromMaybe True (v VU.!? idx'))
+    putStr (debugShowWithDepth rp idx')
+    putStr ": "
+    print i
+    pure $ indexChoice rp idx'
+
+{- | Index the list of choices, if there are no choices left
+default to false. Indexing with a negative number gives True.
+-}
+indexChoice :: RPath -> Int -> Bool
+indexChoice (RPath v) idx
+  | idx < 0 = True
+  | otherwise = fromMaybe False (v VU.!? idx)
+
+numberOfChoices :: RPath -> Int
+numberOfChoices (RPath v) = VU.length v
 
 -- | Create a reduction path from a list of choices
 fromChoiceList :: [Bool] -> RPath
@@ -44,6 +62,11 @@ fromChoiceList = RPath . VU.fromList
 toChoiceList :: RPath -> [Bool]
 toChoiceList = VU.toList . rPathAsVector
 
+debugShowWithDepth :: RPath -> Int -> String
+debugShowWithDepth rp i =
+  (map (bool '0' '1') . take (i + 1) . toChoiceList $ rp)
+    <> replicate (numberOfChoices rp - i - 1) '*'
+
 instance Show RPath where
   show = show . map (bool '0' '1') . toChoiceList
 
diff --git a/rtree/test/expected/double-let-expr-red b/rtree/test/expected/double-let-expr-red
new file mode 100644
index 0000000000000000000000000000000000000000..96086ed521730bce782193e062d01da9e963894b
--- /dev/null
+++ b/rtree/test/expected/double-let-expr-red
@@ -0,0 +1,9 @@
+1: x := 1; y := 2; x + y
+0: -
+1: y := 2; 1 + y
+0: -
+1: 1 + 2
+0: 2
+0: 1
+0: 3
+1: 1 + 2
diff --git a/rtree/test/expected/double-let-expr-red-exp b/rtree/test/expected/double-let-expr-red-exp
new file mode 100644
index 0000000000000000000000000000000000000000..2cba9010b30853f2ae2e82ef9e367eabd92fff2c
--- /dev/null
+++ b/rtree/test/expected/double-let-expr-red-exp
@@ -0,0 +1,11 @@
+1: x := 1; y := 2; x + y
+0: -
+1: y := 2; 1 + y
+0: -
+0: -
+1: 1 + 2
+0: -
+0: 2
+0: 1
+0: 3
+1: 1 + 2
diff --git a/rtree/test/expected/double-overloading-let-expr-red b/rtree/test/expected/double-overloading-let-expr-red
new file mode 100644
index 0000000000000000000000000000000000000000..6810214bb17cca53399ddb2fdd5fd481fdeee87a
--- /dev/null
+++ b/rtree/test/expected/double-overloading-let-expr-red
@@ -0,0 +1,9 @@
+1: x := 1; x := 2; x + x
+0: -
+1: x := 2; x + x
+0: -
+1: 2 + 2
+0: 2
+0: 2
+0: 4
+1: 2 + 2
diff --git a/rtree/test/expected/double-overloading-let-expr-red-exp b/rtree/test/expected/double-overloading-let-expr-red-exp
new file mode 100644
index 0000000000000000000000000000000000000000..096282a682bdfd17e3a97b9d565a6c6d99815338
--- /dev/null
+++ b/rtree/test/expected/double-overloading-let-expr-red-exp
@@ -0,0 +1,11 @@
+1: x := 1; x := 2; x + x
+0: -
+1: x := 2; x + x
+0: -
+0: -
+1: 2 + 2
+0: -
+0: 2
+0: 2
+0: 4
+1: 2 + 2
diff --git a/rtree/test/expected/small-let-expr-red b/rtree/test/expected/small-let-expr-red
new file mode 100644
index 0000000000000000000000000000000000000000..b4879179f59bdf72c7f4067e00e2b9f513312a95
--- /dev/null
+++ b/rtree/test/expected/small-let-expr-red
@@ -0,0 +1,7 @@
+1: x := 1; 2 + x
+0: -
+1: 2 + 1
+0: 1
+0: 2
+0: 3
+1: 2 + 1
diff --git a/rtree/test/expected/small-let-expr-red-exp b/rtree/test/expected/small-let-expr-red-exp
new file mode 100644
index 0000000000000000000000000000000000000000..16c26bf00c389231c238e8494dce97a434fe5f17
--- /dev/null
+++ b/rtree/test/expected/small-let-expr-red-exp
@@ -0,0 +1,8 @@
+1: x := 1; 2 + x
+0: -
+1: 2 + 1
+0: -
+0: 1
+0: 2
+0: 3
+1: 2 + 1
diff --git a/rtree/test/expected/small-opr-expr-red b/rtree/test/expected/small-opr-expr-red
new file mode 100644
index 0000000000000000000000000000000000000000..85cbaac74994155a57a3f04b8e8af347e4c693a4
--- /dev/null
+++ b/rtree/test/expected/small-opr-expr-red
@@ -0,0 +1,5 @@
+1: 1 + 2
+0: 2
+0: 1
+0: 3
+1: 1 + 2
diff --git a/rtree/test/expected/small-opr-expr-red-exp b/rtree/test/expected/small-opr-expr-red-exp
new file mode 100644
index 0000000000000000000000000000000000000000..85cbaac74994155a57a3f04b8e8af347e4c693a4
--- /dev/null
+++ b/rtree/test/expected/small-opr-expr-red-exp
@@ -0,0 +1,5 @@
+1: 1 + 2
+0: 2
+0: 1
+0: 3
+1: 1 + 2
diff --git a/rtree/test/src/Control/Monad/IRTreeSpec.hs b/rtree/test/src/Control/Monad/IRTreeSpec.hs
new file mode 100644
index 0000000000000000000000000000000000000000..e3a10de8a652f36219ac031142e898784845dda4
--- /dev/null
+++ b/rtree/test/src/Control/Monad/IRTreeSpec.hs
@@ -0,0 +1,74 @@
+{-# LANGUAGE BlockArguments #-}
+
+module Control.Monad.IRTreeSpec where
+
+import Control.Monad.IRTree
+import qualified Control.Monad.IRTree as IRTree
+import qualified Control.Monad.RTree as RTree
+import Control.Monad.State
+import Control.Monad.Trans.Maybe
+import Data.Bool
+import Data.Expr as Expr
+import Data.IORef (modifyIORef', newIORef, readIORef)
+import qualified Data.Map.Strict as Map
+import Test.Hspec
+import Test.Hspec.GitGolden
+
+spec :: Spec
+spec = describe "examples" do
+  handle "small-opr-expr" $
+    Opr (Cnt 1) (Cnt 2)
+
+  handle "small-let-expr" $
+    Let "x" (Cnt 1) (Opr (Cnt 2) (Var "x"))
+
+  handle "double-let-expr" $
+    Let "x" (Cnt 1) (Let "y" (Cnt 2) (Opr (Var "x") (Var "y")))
+
+  handle "double-overloading-let-expr" $
+    Let "x" (Cnt 1) (Let "x" (Cnt 2) (Opr (Var "x") (Var "x")))
+ where
+  handle str e = describe (str <> " (" <> prettyExprS 0 e ")") do
+    let me = evalStateT (runMaybeT $ Expr.rExpr e) Map.empty
+
+    it "should extract" do
+      IRTree.extract me `shouldBe` Just e
+
+    let re = evalStateT (runMaybeT $ Expr.rExpr e) Map.empty
+
+    let predicate = maybe False (contains isOpr)
+
+    rex <- RTree.reduce (pure . predicate) re
+
+    it "should find an opr" do
+      ref <- newIORef ""
+
+      let test i = do
+            let x = predicate i
+            modifyIORef' ref (\t -> t <> bool "0" "1" x <> ": " <> maybe "-" (flip (prettyExprS 0) "") i <> "\n")
+            pure x
+
+      mex <- IRTree.reduce test me
+      rex `shouldBe` mex
+
+      result <- readIORef ref
+      pure $ golden ("test/expected/" <> str <> "-red") result
+
+    it "should find an opr exponentially" do
+      ref <- newIORef ""
+
+      let test i = do
+            let x = predicate i
+            modifyIORef' ref (\t -> t <> bool "0" "1" x <> ": " <> maybe "-" (flip (prettyExprS 0) "") i <> "\n")
+            pure x
+
+      mex <- IRTree.reduceExp test me
+      rex `shouldBe` mex
+
+      result <- readIORef ref
+      pure $ golden ("test/expected/" <> str <> "-red-exp") result
+
+    it "should reduce like iinputs" do
+      forM_ (RTree.iinputs re) \(ii, e') -> do
+        p <- toPredicate ii
+        IRTree.reduce p me `shouldReturn` Just e'
diff --git a/rtree/test/src/Control/Monad/RTreeSpec.hs b/rtree/test/src/Control/Monad/RTreeSpec.hs
index b4433f14c47c97c0bcdc2cd28bb7e01f2cd1d87d..37c4541e5442803e7a25d0b269a5a266aba2bc75 100644
--- a/rtree/test/src/Control/Monad/RTreeSpec.hs
+++ b/rtree/test/src/Control/Monad/RTreeSpec.hs
@@ -88,19 +88,18 @@ rtreeSpec = describe "RTree" do
         (drawRTree show (rList [1, 2, 3 :: Int]))
 
 examplesSpec :: Spec
-examplesSpec = do
-  describe "rExpr" do
-    handle "small-opr-expr" $
-      Opr (Cnt 1) (Cnt 2)
+examplesSpec = describe "example" do
+  handle "small-opr-expr" $
+    Opr (Cnt 1) (Cnt 2)
 
-    handle "small-let-expr" $
-      Let "x" (Cnt 1) (Opr (Cnt 2) (Var "x"))
+  handle "small-let-expr" $
+    Let "x" (Cnt 1) (Opr (Cnt 2) (Var "x"))
 
-    handle "double-let-expr" $
-      Let "x" (Cnt 1) (Let "y" (Cnt 2) (Opr (Var "x") (Var "y")))
+  handle "double-let-expr" $
+    Let "x" (Cnt 1) (Let "y" (Cnt 2) (Opr (Var "x") (Var "y")))
 
-    handle "double-overloading-let-expr" $
-      Let "x" (Cnt 1) (Let "x" (Cnt 2) (Opr (Var "x") (Var "x")))
+  handle "double-overloading-let-expr" $
+    Let "x" (Cnt 1) (Let "x" (Cnt 2) (Opr (Var "x") (Var "x")))
  where
   handle str e = describe (str <> " (" <> prettyExprS 0 e ")") do
     let me = runMaybeT $ Expr.rExpr e
diff --git a/rtree/test/src/Data/Expr.hs b/rtree/test/src/Data/Expr.hs
index 48ea44d9948f14f95e7b06854967a705803fab8f..ece98559109841109ca17d20e1bca2a064e33f25 100644
--- a/rtree/test/src/Data/Expr.hs
+++ b/rtree/test/src/Data/Expr.hs
@@ -1,20 +1,42 @@
+{-# LANGUAGE BlockArguments #-}
+{-# LANGUAGE DeriveDataTypeable #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE ScopedTypeVariables #-}
 
 module Data.Expr where
 
 import Control.Applicative
 import Control.Monad.Reduce
 import Control.Monad.State
+import Data.Data
 import Data.Functor
 import qualified Data.Map.Strict as Map
+import Test.Hspec
 
 data Expr
   = Var !String
   | Cnt !Int
   | Opr !Expr !Expr
   | Let !String !Expr !Expr
-  deriving (Show, Eq)
+  deriving (Show, Eq, Data)
+
+isOpr :: Expr -> Bool
+isOpr = \case
+  Opr _ _ -> True
+  _a -> False
+
+spec :: Spec
+spec = do
+  describe "contains" do
+    it "handles a small case" do
+      contains isOpr (Opr (Var "x") (Var "y")) `shouldBe` True
+
+contains :: (Data a) => (Expr -> Bool) -> a -> Bool
+contains fn e =
+  gmapQl (||) False (contains fn) e || case cast e of
+    Just (e' :: Expr) -> fn e'
+    Nothing -> False
 
 rExpr
   :: (MonadReducePlus m, MonadState (Map.Map String (Either String Expr)) m)
diff --git a/rtree/test/src/Test/Hspec/GitGolden.hs b/rtree/test/src/Test/Hspec/GitGolden.hs
index 5652c2878e4501f173f953cd1cb03737c14fcced..2bd9e18f94ede72054c0b65de0d1d0f528c5aaf8 100644
--- a/rtree/test/src/Test/Hspec/GitGolden.hs
+++ b/rtree/test/src/Test/Hspec/GitGolden.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE OverloadedRecordDot #-}
 
 module Test.Hspec.GitGolden where
@@ -16,6 +17,11 @@ data GitGolden = GitGolden
   , content :: !String
   }
 
+instance Example (IO GitGolden) where
+  evaluateExample e p a c = do
+    e' <- e
+    evaluateExample e' p a c
+
 instance Example GitGolden where
   evaluateExample e _p _a _c = do
     createDirectoryIfMissing True (takeDirectory e.filename)