narrowVariant :: LNTerm -- ^ The term.
              -> Maybe Int -- ^ The step bound.
              -> WithMaude (Maybe [Variant])
narrowVariant tstart maxdepth =
    reader $ \hnd -> go maxdepth [ Variant [] emptySubstVFresh ] [] hnd
  where
    go :: Maybe Int -> [Variant] -> [Variant] -> MaudeHandle
       -> Maybe [Variant]
    go _        []           explored _ = Just explored
    go (Just 0) _unexplored _explored _ = Nothing
    go n unexplored explored hnd = (\res -> (trace (show (n, unexplored, explored, res, new0, explored', new)) res)) $
        go (fmap pred n) new explored' hnd
      where
        runWithMaude = (`runReader` hnd)
        explored0 = explored++unexplored
        new0 = filter (\newVariant -> varSubst newVariant `notElem` map varSubst explored0)
                 $ concatMap variantsFrom' unexplored
        variants = reverse $ sortOn narrowSeqStepComplexity $ (tag False new0 ++ tag True explored0)
        minimized = filterMaximalBy fst cmp variants
        tag t xs = [ (t,a) | a <- xs]
        (explored',new) = map snd *** map snd $ partition fst minimized
        cmp a b = runWithMaude $ compareSubstVariant tstart (varSubst.snd $ a) (varSubst.snd $ b)

        variantsFrom' (Variant pos0 substComposed) =
          zipWith (\i substComposed' -> Variant (pos0++[i]) substComposed')
                  [1..]
                  (runWithMaude $ variantsFrom tstart substComposed)

-- | @filterMaximalBy flags fastcmp alreadyFiltered cmp xs@ returns a
--   list of maximal elements of @xs@ with respect to @cmp@.
narrowVariant :: LNTerm -- ^ The term.
              -> Maybe Int -- ^ The step bound.
              -> WithMaude (Maybe [Variant])
narrowVariant tstart maxdepth =
    reader $ \hnd -> go maxdepth [ Variant [] emptySubstVFresh ] [] hnd
  where
    go :: Maybe Int -> [Variant] -> [Variant] -> MaudeHandle
       -> Maybe [Variant]
    go _        []           explored _ = Just explored
    go (Just 0) _unexplored _explored _ = Nothing
    go n unexplored explored hnd = (\res -> (trace (show (n, unexplored, explored, res, new0, explored', new)) res)) $
        go (fmap pred n) new explored' hnd
      where
        runWithMaude = (`runReader` hnd)
        explored0 = explored++unexplored
        new0 = filter (\newVariant -> varSubst newVariant `notElem` map varSubst explored0)
                 $ concatMap variantsFrom' unexplored
        variants = reverse $ sortOn narrowSeqStepComplexity $ (tag False new0 ++ tag True explored0)
        minimized = filterMaximalBy fst cmp variants
        tag t xs = [ (t,a) | a <- xs]
        (explored',new) = map snd *** map snd $ partition fst minimized
        cmp a b = runWithMaude $ compareSubstVariant tstart (varSubst.snd $ a) (varSubst.snd $ b)

        variantsFrom' (Variant pos0 substComposed) =
          zipWith (\i substComposed' -> Variant (pos0++[i]) substComposed')
                  [1..]
                  (runWithMaude $ variantsFrom tstart substComposed)

-- | @filterMaximalBy flags fastcmp alreadyFiltered cmp xs@ returns a
--   list of maximal elements of @xs@ with respect to @cmp@.
narrowVariant tstart maxdepth =
    reader $ \hnd -> go maxdepth [ Variant [] emptySubstVFresh ] [] hnd
  where
    go :: Maybe Int -> [Variant] -> [Variant] -> MaudeHandle
       -> Maybe [Variant]
    go _        []           explored _ = Just explored
    go (Just 0) _unexplored _explored _ = Nothing
    go n unexplored explored hnd = (\res -> (trace (show (n, unexplored, explored, res, new0, explored', new)) res)) $
        go (fmap pred n) new explored' hnd
      where
        runWithMaude = (`runReader` hnd)
        explored0 = explored++unexplored
        new0 = filter (\newVariant -> varSubst newVariant `notElem` map varSubst explored0)
                 $ concatMap variantsFrom' unexplored
        variants = reverse $ sortOn narrowSeqStepComplexity $ (tag False new0 ++ tag True explored0)
        minimized = filterMaximalBy fst cmp variants
        tag t xs = [ (t,a) | a <- xs]
        (explored',new) = map snd *** map snd $ partition fst minimized
        cmp a b = runWithMaude $ compareSubstVariant tstart (varSubst.snd $ a) (varSubst.snd $ b)

        variantsFrom' (Variant pos0 substComposed) =
          zipWith (\i substComposed' -> Variant (pos0++[i]) substComposed')
                  [1..]
                  (runWithMaude $ variantsFrom tstart substComposed)

-- | @filterMaximalBy flags fastcmp alreadyFiltered cmp xs@ returns a
--   list of maximal elements of @xs@ with respect to @cmp@.