packages feed

ansiform-0.7.8.5: src/Ansiform/Internal/Utils.hs

module Ansiform.Internal.Utils where

--------------------------------------------------------------------------------
import qualified Data.List as List
import           Data.Maybe (fromMaybe)


-- Numbers
--------------------------------------------------------------------------------
-- Version of maximum that takes a default, so it doesn't fail.
maximum' :: Ord a => a -> [a] -> a
maximum' = foldr max

-- Version of minimum that takes a default, so it doesn't fail.
minimum' :: Ord a => a -> [a] -> a
minimum' = foldr min

-- Calculates the average value from a list of Ints.
average :: [Int] -> Int
average xs = case xs of [] -> 0; _ -> div (sum xs) (length xs)


-- Lists
--------------------------------------------------------------------------------
-- Version of head that returns a maybe.
headMaybe :: [a] -> Maybe a
headMaybe [] = Nothing
headMaybe (x:_) = Just x

-- Version of head that takes a default.
head' :: a -> [a] -> a
head' d [] = d
head' _ (x:_) = x

-- Version of last that returns a maybe. Still doesn't work for infinite lists.
lastMaybe :: [a] -> Maybe a
lastMaybe [] = Nothing
lastMaybe (x:xs) = Just (last' x xs)

-- Version of last that takes a default.
last' :: a -> [a] -> a
last' d [] = d
last' _ (x:xs) = last' x xs


-- Reverses and concats a list simultaneously, used to avoid appending.
concatRev :: [[a]] -> [a]
concatRev = foldr (flip (++)) []

concatRev' :: [[a]] -> [a]
concatRev' = List.foldl' (flip (++)) []


-- Checks if a List has at least a given number of items or more.
atLeastLength :: Int -> [a] -> Bool
atLeastLength n = not . null . drop (n-1)

-- Checks if a List has exactly a given number of items.
--    Doesn't run the rest of the list if it fails.
exactLength :: Int -> [a] -> Bool
exactLength n as
        | n < 0 = False
        | n == 0 = null as
        | otherwise = lengthTest 0 as
      where  
        lengthTest c as'
            | null as' = c == n
            | c > n = False
            | otherwise = lengthTest (c+1) (drop 1 as')

-- Inserts an element in a list at a given index.
insertAt :: Int -> a -> [a] -> [a]
insertAt n e es = take n es ++ [e] ++ drop n es

-- GroupsBy using any binary operation, not only equality. (Brandon Simmons)
groupBy' :: (a -> a -> Bool) -> [a] -> [[a]]
groupBy' _ [] = []
groupBy' c (a:as) = (a:ys) : groupBy' c zs
    where (ys,zs) = spanC a as
          spanC _ [] = ([], [])
          spanC a' (x:xs)
            | a' `c` x = let (ps,qs) = spanC x xs
                          in (x:ps,qs)
            | otherwise = ([], x:xs)

-- Function to find the point to split a list of Ints 
--    when their sum overflows an Int threshold.
splitPoint :: [Int] -> Int -> Int
splitPoint wl w = sumTest 0 0 wl
        where
          sumTest s i cs
               | curSum <= w && not (null cs) = sumTest curSum (i + 1) (drop 1 cs)
               | otherwise = i
            where c = fromMaybe 0 $ headMaybe cs
                  curSum = s + c

-- Monads
--------------------------------------------------------------------------------

-- Shorthand for returning unit.
return_ :: Monad m => m ()
return_ = return ()