recursion-algorithms

groupBy

module Algorithms.List.BasicOperations.GroupBy where

import Control.Arrow (first)
import Data.Functor.Foldable

groupBy is defined in standard Data.List module of base package. Its spec is following

{- @
   groupBy :: (a -> a -> Bool) -> [a] -> [[a]]
   groupBy _  []     = []
   groupBy eq (x:xs) = (x:ys) : groupBy eq zs
                       where (ys,zs) = span (eq x) xs
   @
-}

We can implement groupBy as an instance of paramorphism.

{- | >>> groupByAna (==) "Mississippi"
["M","i","ss","i","ss","i","pp","i"]
-}
groupByAna :: (a -> a -> Bool) -> [a] -> [[a]]
groupByAna eq = ana psi
  where
    psi = \ case
      []   -> Nil
      x:xs -> uncurry Cons (first (x :) (span (eq x) xs))

And we can also implement groupBy as an instance of catamorphism. *

{- | >>> groupByCata (==) "Mississippi"
["M","i","ss","i","ss","i","pp","i"]
-}
groupByCata :: (a -> a -> Bool) -> [a] -> [[a]]
groupByCata g = cata alg
  where
    alg = \ case
      Nil           -> []
      Cons x []     -> [[x]]
      Cons x (ys@(y:_):yss)
        | g x y     -> (x:ys):yss
        | otherwise -> [x]:ys:yss