-- | Similar to 'Data.List.NonEmpty.groupBy1' but with a function argument that
-- only needs transitivity, not equality.
--
-- See the following on how 'groupBy' expects equality:
-- http://stackoverflow.com/questions/1316365/haskell-surprising-behavior-of-groupby
groupBy1Transitive :: (a -> a -> Bool) -> NonEmpty a -> NonEmpty (NonEmpty a)
groupBy1Transitive cmp = go
  where
    go (x:|[]) = (x :| []) :| []
    go (x:|xs@(x2:rest)) =
      case grouped of
         [] ->  (x :| []) <| go (x2:|rest)
         (g:gs) -> let grouping = g :| gs in
             case ungrouped of
                 []     -> grouping :| []
                 (u:us) -> grouping <| go (u:|us)
      where
        (grouped, ungrouped) = spanNeighbor cmp (x:xs)

-- | Run a comparison function among neighbors.
groupBy1Transitive :: (a -> a -> Bool) -> NonEmpty a -> NonEmpty (NonEmpty a)
groupBy1Transitive cmp = go
  where
    go (x:|[]) = (x :| []) :| []
    go (x:|xs@(x2:rest)) =
      case grouped of
         [] ->  (x :| []) <| go (x2:|rest)
         (g:gs) -> let grouping = g :| gs in
             case ungrouped of
                 []     -> grouping :| []
                 (u:us) -> grouping <| go (u:|us)
      where
        (grouped, ungrouped) = spanNeighbor cmp (x:xs)

-- | Run a comparison function among neighbors.
groupBy1Transitive cmp = go
  where
    go (x:|[]) = (x :| []) :| []
    go (x:|xs@(x2:rest)) =
      case grouped of
         [] ->  (x :| []) <| go (x2:|rest)
         (g:gs) -> let grouping = g :| gs in
             case ungrouped of
                 []     -> grouping :| []
                 (u:us) -> grouping <| go (u:|us)
      where
        (grouped, ungrouped) = spanNeighbor cmp (x:xs)

-- | Run a comparison function among neighbors.