Advise-me-0.1: src/Util/List.hs
-----------------------------------------------------------------------------
-- Copyright 2019, Advise-Me project team. This file is distributed under
-- the terms of the Apache License 2.0. For more information, see the files
-- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution.
-----------------------------------------------------------------------------
-- |
-- Maintainer : bastiaan.heeren@ou.nl
-- Stability : provisional
-- Portability : portable (depends on ghc)
--
-----------------------------------------------------------------------------
module Util.List
( safeHead, returnOnJustM, groupings, cartProd
, selections, safeSingleton, safeLast, appLast, modifyAt
, index
, concatMapM
, groupBy'
, orderBy
) where
import Data.Function (on)
import Data.List (elemIndex, sortBy, groupBy)
import Control.Arrow (second, (&&&))
safeHead :: [a] -> Maybe a
safeHead [] = Nothing
safeHead (x:_) = Just x
safeLast :: [a] -> Maybe a
safeLast = foldl (\_ a -> Just a) Nothing
appLast :: (a -> a) -> [a] -> [a]
appLast _ [] = []
appLast f [a] = [f a]
appLast f (x:xs) = x : appLast f xs
modifyAt :: Int -> (a -> a) -> [a] -> [a]
modifyAt _ _ [] = []
modifyAt n f (x:xs)
| n == 0 = f x : xs
| otherwise = x : modifyAt (n-1) f xs
safeSingleton :: [a] -> Maybe a
safeSingleton [a] = Just a
safeSingleton _ = Nothing
cartProd :: [a] -> [b] -> [(a,b)]
cartProd xs ys = do
x <- xs
y <- ys
return (x,y)
selections :: [a] -> [(a,[a])]
selections [] = []
selections (x:xs) = (x,xs) : map (second (x:)) (selections xs)
returnOnJustM :: (Monad m, Show a) => (a -> m (Maybe b)) -> [a] -> m (Maybe (b, [a]))
returnOnJustM _ [] = return Nothing
returnOnJustM f input =
returnAndRetain f [] input
where
returnAndRetain _ _ [] = return Nothing
returnAndRetain f old new@(x:xs) = do
fx <- f x
case fx of
Nothing -> returnAndRetain f (old ++ [x]) xs
Just b -> return $ Just (b, old ++ new)
groupings :: [a] -> [b] -> [[(a,b)]]
groupings [] _ = [[]]
groupings _ [] = [[]]
groupings (a:as) bs = concatMap (\(x,xs) -> map ((a,x):) $ groupings as xs) $ selections bs
-- | Find index of an element in a list.
index :: Eq a => [a] -> a -> Maybe Int
index list = flip elemIndex list
-- | Monadic 'concatMap'.
concatMapM :: Monad m => (a -> m [b]) -> [a] -> m [b]
concatMapM f xs = concat <$> mapM f xs
-- | Alternative to 'Data.List.groupBy', where only adjacent elements are
-- compared - so the predicate does not assume transitivity.
groupBy' :: (a -> a -> Bool) -> [a] -> [[a]]
groupBy' _ [] = []
groupBy' _ [x] = [[x]]
groupBy' predicate (x:y:xs)
| predicate x y = let sameGroup:diffGroups = groupBy' predicate (y:xs)
in (x:sameGroup):diffGroups
| otherwise = [x] : groupBy' predicate (y:xs)
-- | Alternative to 'Data.List.groupBy', in which the list is sorted and grouped
-- on a certain attribute, and each group is labelled with said attribute.
orderBy :: (Ord b) => (a->b) -> [a] -> [(b,[a])]
orderBy attribute
= map (fst . head &&& map snd)
. groupBy ((==) `on` fst)
. sortBy (compare `on` fst)
. map (attribute &&& id)