    -- |
    -- Module      : Foundation.Collection.List
    -- License     : BSD-style
    -- Maintainer  : Vincent Hanquez <vincent@snarc.org>
    -- Stability   : experimental
    -- Portability : portable
    --
    module Foundation.Collection.List
        ( wordsWhen
        , revTake
        , revDrop
        , revSplitAt
        , breakEnd
        , uncons
        , unsnoc
        ) where

    import qualified Data.List
    import           Data.Tuple (swap)
    import           Basement.Compat.Base
    import           Foundation.Numerical

    -- | Simple helper to split a list repeatly when the predicate match
    wordsWhen     :: (x -> Bool) -> [x] -> [[x]]
    wordsWhen :: forall x. (x -> Bool) -> [x] -> [[x]]
    wordsWhen x -> Bool
    _ [] = [[]]
    wordsWhen x -> Bool
    p [x]
    is = [x] -> [[x]]
    loop [x]
    is
      where
        loop :: [x] -> [[x]]
    loop [x]
    s =
            let ([x]
    w, [x]
    s') = (x -> Bool) -> [x] -> ([x], [x])
    forall a. (a -> Bool) -> [a] -> ([a], [a])
    Data.List.break x -> Bool
    p [x]
    s
             in case [x]
    s' of
                    []   -> [[x]
    w]
                    x
    _:[x]
    xs -> [x]
    w [x] -> [[x]] -> [[x]]
    forall a. a -> [a] -> [a]
    : [x] -> [[x]]
    loop [x]
    xs

    revTake :: Int -> [a] -> [a]
    revTake :: forall a. Int -> [a] -> [a]
    revTake Int
    n [a]
    l = Int -> [a] -> [a]
    forall a. Int -> [a] -> [a]
    Data.List.drop (Int
    len Int -> Int -> Difference Int
    forall a. Subtractive a => a -> a -> Difference a
    - Int
    n) [a]
    l
      where
        len :: Int
    len = [a] -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    Data.List.length [a]
    l

    revDrop :: Int -> [a] -> [a]
    revDrop :: forall a. Int -> [a] -> [a]
    revDrop Int
    n [a]
    l = Int -> [a] -> [a]
    forall a. Int -> [a] -> [a]
    Data.List.take (Int
    len Int -> Int -> Difference Int
    forall a. Subtractive a => a -> a -> Difference a
    - Int
    n) [a]
    l
      where
        len :: Int
    len = [a] -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    Data.List.length [a]
    l

    revSplitAt :: Int -> [a] -> ([a],[a])
    revSplitAt :: forall a. Int -> [a] -> ([a], [a])
    revSplitAt Int
    n [a]
    l = ([a], [a]) -> ([a], [a])
    forall a b. (a, b) -> (b, a)
    swap (([a], [a]) -> ([a], [a])) -> ([a], [a]) -> ([a], [a])
    forall a b. (a -> b) -> a -> b
    $ Int -> [a] -> ([a], [a])
    forall a. Int -> [a] -> ([a], [a])
    Data.List.splitAt (Int
    len Int -> Int -> Difference Int
    forall a. Subtractive a => a -> a -> Difference a
    - Int
    n) [a]
    l
      where
        len :: Int
    len = [a] -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    Data.List.length [a]
    l

    breakEnd :: (a -> Bool) -> [a] -> ([a], [a])
    breakEnd :: forall a. (a -> Bool) -> [a] -> ([a], [a])
    breakEnd a -> Bool
    predicate [a]
    l =
        let ([a]
    l1,[a]
    l2) = (a -> Bool) -> [a] -> ([a], [a])
    forall a. (a -> Bool) -> [a] -> ([a], [a])
    Data.List.break a -> Bool
    predicate ([a] -> [a]
    forall a. [a] -> [a]
    Data.List.reverse [a]
    l)
         in if [a] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    Data.List.null [a]
    l2 then ([a]
    l, []) else ([a] -> [a]
    forall a. [a] -> [a]
    Data.List.reverse [a]
    l2, [a] -> [a]
    forall a. [a] -> [a]
    Data.List.reverse [a]
    l1)

    uncons :: [a] -> Maybe (a, [a])
    uncons :: forall a. [a] -> Maybe (a, [a])
    uncons []     = Maybe (a, [a])
    forall a. Maybe a
    Nothing
    uncons (a
    x:[a]
    xs) = (a, [a]) -> Maybe (a, [a])
    forall a. a -> Maybe a
    Just (a
    x,[a]
    xs)

    unsnoc :: [a] -> Maybe ([a], a)
    unsnoc :: forall a. [a] -> Maybe ([a], a)
    unsnoc []       = Maybe ([a], a)
    forall a. Maybe a
    Nothing
    unsnoc [a
    x]      = ([a], a) -> Maybe ([a], a)
    forall a. a -> Maybe a
    Just ([], a
    x)
    unsnoc [a
    x,a
    y]    = ([a], a) -> Maybe ([a], a)
    forall a. a -> Maybe a
    Just ([a
    x], a
    y)
    unsnoc (a
    x:xs :: [a]
    xs@(a
    _:[a]
    _)) = ([a], a) -> Maybe ([a], a)
    forall a. a -> Maybe a
    Just (([a], a) -> Maybe ([a], a)) -> ([a], a) -> Maybe ([a], a)
    forall a b. (a -> b) -> a -> b
    $ [a] -> [a] -> ([a], a)
    forall {a}. [a] -> [a] -> ([a], a)
    loop [a
    x] [a]
    xs
      where
        loop :: [a] -> [a] -> ([a], a)
    loop [a]
    acc [a
    y]    = ([a] -> [a]
    forall a. [a] -> [a]
    Data.List.reverse [a]
    acc, a
    y)
        loop [a]
    acc (a
    y:[a]
    ys) = [a] -> [a] -> ([a], a)
    loop (a
    ya -> [a] -> [a]
    forall a. a -> [a] -> [a]
    :[a]
    acc) [a]
    ys
        loop [a]
    _   [a]
    _      = [Char] -> ([a], a)
    forall a. HasCallStack => [Char] -> a
    error [Char]
    "impossible"