-- |
-- 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') = 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 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 = forall a. Int -> [a] -> [a]
Data.List.drop (Int
len forall a. Subtractive a => a -> a -> Difference a
- Int
n) [a]
l
  where
    len :: Int
len = 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 = forall a. Int -> [a] -> [a]
Data.List.take (Int
len forall a. Subtractive a => a -> a -> Difference a
- Int
n) [a]
l
  where
    len :: Int
len = 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 = forall a b. (a, b) -> (b, a)
swap forall a b. (a -> b) -> a -> b
$ forall a. Int -> [a] -> ([a], [a])
Data.List.splitAt (Int
len forall a. Subtractive a => a -> a -> Difference a
- Int
n) [a]
l
  where
    len :: Int
len = 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) = forall a. (a -> Bool) -> [a] -> ([a], [a])
Data.List.break a -> Bool
predicate (forall a. [a] -> [a]
Data.List.reverse [a]
l)
     in if forall (t :: * -> *) a. Foldable t => t a -> Bool
Data.List.null [a]
l2 then ([a]
l, []) else (forall a. [a] -> [a]
Data.List.reverse [a]
l2, forall a. [a] -> [a]
Data.List.reverse [a]
l1)

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

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