---------------------------------------------------------------------- -- | -- Maintainer : PL -- Stability : (stable) -- Portability : (portable) -- -- > CVS $Date: 2005/10/26 18:47:16 $ -- > CVS $Author: bringert $ -- > CVS $Revision: 1.6 $ -- -- Basic functions not in the standard libraries ----------------------------------------------------------------------------- module GF.Data.Utilities(module GF.Data.Utilities, module PGF.Utilities) where import Data.Maybe import Data.List import Control.Monad (MonadPlus(..),liftM,when) import PGF.Utilities -- * functions on lists sameLength :: [a] -> [a] -> Bool sameLength [] [] = True sameLength (_:xs) (_:ys) = sameLength xs ys sameLength _ _ = False notLongerThan, longerThan :: Int -> [a] -> Bool notLongerThan n = null . snd . splitAt n longerThan n = not . notLongerThan n lookupList :: Eq a => a -> [(a, b)] -> [b] lookupList a [] = [] lookupList a (p:ps) | a == fst p = snd p : lookupList a ps | otherwise = lookupList a ps split :: [a] -> ([a], [a]) split (x : y : as) = (x:xs, y:ys) where (xs, ys) = split as split as = (as, []) splitBy :: (a -> Bool) -> [a] -> ([a], [a]) splitBy p [] = ([], []) splitBy p (a : as) = if p a then (a:xs, ys) else (xs, a:ys) where (xs, ys) = splitBy p as foldMerge :: (a -> a -> a) -> a -> [a] -> a foldMerge merge zero = fm where fm [] = zero fm [a] = a fm abs = let (as, bs) = split abs in fm as `merge` fm bs select :: [a] -> [(a, [a])] select [] = [] select (x:xs) = (x,xs) : [ (y,x:ys) | (y,ys) <- select xs ] updateNth :: (a -> a) -> Int -> [a] -> [a] updateNth update 0 (a : as) = update a : as updateNth update n (a : as) = a : updateNth update (n-1) as updateNthM :: Monad m => (a -> m a) -> Int -> [a] -> m [a] updateNthM update 0 (a : as) = liftM (:as) (update a) updateNthM update n (a : as) = liftM (a:) (updateNthM update (n-1) as) -- | Like 'init', but returns the empty list when the input is empty. safeInit :: [a] -> [a] safeInit [] = [] safeInit xs = init xs -- | Sorts and then groups elements given an ordering of the -- elements. sortGroupBy :: (a -> a -> Ordering) -> [a] -> [[a]] sortGroupBy f = groupBy (compareEq f) . sortBy f -- | Take the union of a list of lists. unionAll :: Eq a => [[a]] -> [a] unionAll = nub . concat -- | Like 'lookup', but fails if the argument is not found, -- instead of returning Nothing. lookup' :: (Show a, Eq a) => a -> [(a,b)] -> b lookup' x = fromMaybe (error $ "Not found: " ++ show x) . lookup x -- | Like 'find', but fails if nothing is found. find' :: (a -> Bool) -> [a] -> a find' p = fromJust . find p -- | Set a value in a lookup table. tableSet :: Eq a => a -> b -> [(a,b)] -> [(a,b)] tableSet x y [] = [(x,y)] tableSet x y (p@(x',_):xs) | x' == x = (x,y):xs | otherwise = p:tableSet x y xs -- | Group tuples by their first elements. buildMultiMap :: Ord a => [(a,b)] -> [(a,[b])] buildMultiMap = map (\g -> (fst (head g), map snd g) ) . sortGroupBy (compareBy fst) -- * equality functions -- | Use an ordering function as an equality predicate. compareEq :: (a -> a -> Ordering) -> a -> a -> Bool compareEq f x y = case f x y of EQ -> True _ -> False -- * ordering functions compareBy :: Ord b => (a -> b) -> a -> a -> Ordering compareBy f = both f compare both :: (a -> b) -> (b -> b -> c) -> a -> a -> c both f g x y = g (f x) (f y) -- * functions on pairs apFst :: (a -> a') -> (a, b) -> (a', b) apFst f (a, b) = (f a, b) apSnd :: (b -> b') -> (a, b) -> (a, b') apSnd f (a, b) = (a, f b) apBoth :: (a -> b) -> (a, a) -> (b, b) apBoth f (x, y) = (f x, f y) -- * functions on lists of pairs mapFst = map . apFst mapSnd = map . apSnd mapBoth = map . apBoth -- * functions on monads -- | Return the given value if the boolean is true, els return 'mzero'. whenMP :: MonadPlus m => Bool -> a -> m a whenMP b x = if b then return x else mzero whenM bm m = flip when m =<< bm repeatM m = whenM m (repeatM m) -- * functions on Maybes -- | Returns true if the argument is Nothing or Just [] nothingOrNull :: Maybe [a] -> Bool nothingOrNull = maybe True null -- * functions on functions -- | Apply all the functions in the list to the argument. foldFuns :: [a -> a] -> a -> a foldFuns fs x = foldl (flip ($)) x fs -- | Fixpoint iteration. fix :: Eq a => (a -> a) -> a -> a fix f x = let x' = f x in if x' == x then x else fix f x' -- * functions on strings -- | Join a number of lists by using the given glue -- between the lists. join :: [a] -- ^ glue -> [[a]] -- ^ lists to join -> [a] join g = concat . intersperse g -- * ShowS-functions nl :: ShowS nl = showChar '\n' sp :: ShowS sp = showChar ' ' wrap :: String -> ShowS -> String -> ShowS wrap o s c = showString o . s . showString c concatS :: [ShowS] -> ShowS concatS = foldr (.) id unwordsS :: [ShowS] -> ShowS unwordsS = joinS " " unlinesS :: [ShowS] -> ShowS unlinesS = joinS "\n" joinS :: String -> [ShowS] -> ShowS joinS glue = concatS . intersperse (showString glue)