-- |
-- Module      :  Sublists
-- Copyright   :  (c) OleksandrZhabenko 2021
-- License     :  MIT
-- Stability   :  Experimental
-- Maintainer  :  olexandr543@yahoo.com
--
-- Allows to split lists into sublists with some patterns by quantity.

module Sublists where

{-| Splits the input second argument into sublists each one containing the @n@ elements where the number is taken as the
sequential element in the first argument starting from the left to the right. If the number is less than 1 then the
corresponding sublist is empty. If all the elements in the first argument are less than 1 then returns an infinite lazy list of
[] as its elements (probably not the needed case). When all the elements of the first argument ends and there are elements in
the second argument being not already processed then the function reinitializes itself with the prior first argument and the
rest of the unprocessed elements in the second argument. This leads to the *cycling behaviour*.

If the first argument is less than 1 then returns an infinite lazy list of the [] as its elements (probably not the needed case).

Similar functions are in the @list-grouping@ and @split@ packages, but they do not have cycling behaviour and have another realization. -}
intoRegularSublists :: [Int] -> [a] -> [[a]]
intoRegularSublists :: [Int] -> [a] -> [[a]]
intoRegularSublists (Int
n:[Int]
ns) [a]
xs 
 | [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [a]
xs = []
 | Bool
otherwise = [a]
ts [a] -> [[a]] -> [[a]]
forall a. a -> [a] -> [a]
: [Int] -> [a] -> [Int] -> [[a]]
forall a. [Int] -> [a] -> [Int] -> [[a]]
intoRegularSublists' [Int]
ns [a]
zs (Int
nInt -> [Int] -> [Int]
forall a. a -> [a] -> [a]
:[Int]
ns)
     where ([a]
ts, [a]
zs) = Int -> [a] -> ([a], [a])
forall a. Int -> [a] -> ([a], [a])
splitAt Int
n [a]
xs
           intoRegularSublists' :: [Int] -> [a] -> [Int] -> [[a]]
intoRegularSublists' (Int
r:[Int]
rs) [a]
ys [Int]
us
             | [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [a]
ys = []
             | Bool
otherwise = [a]
ws [a] -> [[a]] -> [[a]]
forall a. a -> [a] -> [a]
: [Int] -> [a] -> [Int] -> [[a]]
intoRegularSublists' [Int]
rs [a]
vs [Int]
us
                 where ([a]
ws,[a]
vs) = Int -> [a] -> ([a], [a])
forall a. Int -> [a] -> ([a], [a])
splitAt Int
r [a]
ys
           intoRegularSublists' [Int]
_ [a]
ys [Int]
us = [Int] -> [a] -> [Int] -> [[a]]
intoRegularSublists' [Int]
us [a]
ys [Int]
us
intoRegularSublists [Int]
_ [a]
xs = [[a]
xs]
{-# INLINABLE intoRegularSublists #-}

{-| A monadic variant of the 'intoRegularSublists' where the first argument is taken from the monadic function. -}
intoRegularSublistsM :: (Monad m)
  => (a -> m [Int]) -- ^ A monadic function to obtain the argument for the regularization.
  -> a -- ^ An initial element (seed) for the monadic function.
  -> [b] -- ^ A list to be splitted into the sublists.
  -> m [[b]]
intoRegularSublistsM :: (a -> m [Int]) -> a -> [b] -> m [[b]]
intoRegularSublistsM a -> m [Int]
f a
seed [b]
xs
 | [b] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [b]
xs = [[b]] -> m [[b]]
forall (m :: * -> *) a. Monad m => a -> m a
return []
 | Bool
otherwise = a -> m [Int]
f a
seed m [Int] -> ([Int] -> m [[b]]) -> m [[b]]
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \[Int]
ns -> [[b]] -> m [[b]]
forall (m :: * -> *) a. Monad m => a -> m a
return ([[b]] -> m [[b]]) -> ([b] -> [[b]]) -> [b] -> m [[b]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Int] -> [b] -> [[b]]
forall a. [Int] -> [a] -> [[a]]
intoRegularSublists [Int]
ns ([b] -> m [[b]]) -> [b] -> m [[b]]
forall a b. (a -> b) -> a -> b
$ [b]
xs
{-# INLINABLE intoRegularSublistsM #-}