{- |
Description: Pack duplicates in a list
Copyright: Copyright (C) 2021 Yoo Chung
License: GPL-3.0-or-later
Maintainer: dev@chungyc.org

Some solutions to "Problems.P09" of Ninety-Nine Haskell "Problems".
-}
module Solutions.P09 (pack, pack') where

import           Data.List (group)

-- | Pack consecutive duplicates of list elements into sublists.
-- If a list contains repeated elements, they should be placed in separate sublists.
--
-- Extract consecutive duplicates from the list, and repeat.
pack :: Eq a => [a] -> [[a]]
pack :: forall a. Eq a => [a] -> [[a]]
pack [] = []
pack [a]
xs = [a]
duplicates [a] -> [[a]] -> [[a]]
forall a. a -> [a] -> [a]
: [a] -> [[a]]
forall a. Eq a => [a] -> [[a]]
pack [a]
remainder
  where ([a]
duplicates, [a]
remainder) = [a] -> ([a], [a])
forall a. Eq a => [a] -> ([a], [a])
extract [a]
xs

-- | Extract consecutive duplicates in front of the list into their own list.
-- Returns the consecutive duplicates in the first element,
-- and the remainder of the list in the second element.
extract :: Eq a => [a] -> ([a], [a])
extract :: forall a. Eq a => [a] -> ([a], [a])
extract (a
x : ys :: [a]
ys@(a
y : [a]
_))
  | a
x a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
y    = let ([a]
d, [a]
r) = [a] -> ([a], [a])
forall a. Eq a => [a] -> ([a], [a])
extract [a]
ys in (a
x a -> [a] -> [a]
forall a. a -> [a] -> [a]
: [a]
d, [a]
r)
  | Bool
otherwise = ([a
x], [a]
ys)
extract [a]
l = ([a]
l, [])

-- | Pack consecutive duplicates of list elements into sublists.
-- If a list contains repeated elements, they should be placed in separate sublists.
--
-- Cheat by using 'group'.
pack' :: Eq a => [a] -> [[a]]
pack' :: forall a. Eq a => [a] -> [[a]]
pack' = [a] -> [[a]]
forall a. Eq a => [a] -> [[a]]
group