filterMaximalBy alreadyFiltered cmp xs0 =
    go (last xs0) (init xs0,[])
  where
    go x ([],[])  = [x]
    go x (y:todo,done)
      -- x and y have already been filtered earlier and are therefore incomparable
      | alreadyFiltered x && alreadyFiltered y = go x (todo,y:done)
      -- either x or y is new, so we have to compare the two
      | otherwise
      = case cmp x y of
          Nothing -> go x (todo,y:done)
          Just EQ | alreadyFiltered x -> keepx
                  | otherwise -> keepy
          Just GT -> keepx
          Just LT -> keepy
      where keepx = go x (todo,done)
            keepy = go y (todo++done,[])
    -- x is maximal, start comparing a new element to the others
    go x ([],y:done)   = x:(go y (reverse done,[]))

-- | This is used to sort narrowing steps such that similar steps are close
filterMaximalBy alreadyFiltered cmp xs0 =
    go (last xs0) (init xs0,[])
  where
    go x ([],[])  = [x]
    go x (y:todo,done)
      -- x and y have already been filtered earlier and are therefore incomparable
      | alreadyFiltered x && alreadyFiltered y = go x (todo,y:done)
      -- either x or y is new, so we have to compare the two
      | otherwise
      = case cmp x y of
          Nothing -> go x (todo,y:done)
          Just EQ | alreadyFiltered x -> keepx
                  | otherwise -> keepy
          Just GT -> keepx
          Just LT -> keepy
      where keepx = go x (todo,done)
            keepy = go y (todo++done,[])
    -- x is maximal, start comparing a new element to the others
    go x ([],y:done)   = x:(go y (reverse done,[]))

-- | This is used to sort narrowing steps such that similar steps are close
filterMaximalBy alreadyFiltered cmp xs0 =
    go (last xs0) (init xs0,[])
  where
    go x ([],[])  = [x]
    go x (y:todo,done)
      -- x and y have already been filtered earlier and are therefore incomparable
      | alreadyFiltered x && alreadyFiltered y = go x (todo,y:done)
      -- either x or y is new, so we have to compare the two
      | otherwise
      = case cmp x y of
          Nothing -> go x (todo,y:done)
          Just EQ | alreadyFiltered x -> keepx
                  | otherwise -> keepy
          Just GT -> keepx
          Just LT -> keepy
      where keepx = go x (todo,done)
            keepy = go y (todo++done,[])
    -- x is maximal, start comparing a new element to the others
    go x ([],y:done)   = x:(go y (reverse done,[]))

-- | This is used to sort narrowing steps such that similar steps are close