This file contains some generic utility stuff > {-# LANGUAGE FlexibleContexts #-} > module Database.HsSqlPpp.Utils.Utils where > > import Data.List > import Data.Either > import Data.Char > import Control.Arrow > import Control.Monad.Error > import Control.Applicative used to mix regular function composition and >>= in monads, so the order of application stays the same instead of going backwards when (.) is used > infixl 9 |> > (|>) :: (a -> b) -> (b -> c) -> a -> c > (|>) = flip (.) > > errorWhen :: (Error a) => Bool -> a -> Either a () > errorWhen cond = when cond . Left > > returnWhen :: (Monad m) => Bool -> a -> m a -> m a > returnWhen c t t1 = if c then return t else t1 > > liftME :: a -> Maybe b -> Either a b > liftME d m = case m of > Nothing -> Left d > Just b -> Right b > > both :: (a->b) -> (a,a) -> (b,b) > both fn = fn *** fn > > (<:>) :: (Applicative f) => > f a -> f [a] -> f [a] > (<:>) a b = (:) <$> a <*> b > > eitherToMaybe :: Either a b -> Maybe b > eitherToMaybe (Left _) = Nothing > eitherToMaybe (Right b) = Just b > > fromRight :: b -> Either a b -> b > fromRight b (Left _) = b > fromRight _ (Right r) = r > > fromLeft :: a -> Either a b -> a > fromLeft _ (Left l) = l > fromLeft a (Right _) = a > > mapEither :: (a->c) -> (b->d) -> Either a b -> Either c d > mapEither l _ (Left a) = Left $ l a > mapEither _ r (Right b) = Right $ r b > > mapRight :: (b -> c) -> Either a b -> Either a c > mapRight = mapEither id > > mapLeft :: (a -> c) -> Either a b -> Either c b > mapLeft l = mapEither l id > > isRight :: Either a b -> Bool > isRight (Right _) = True > isRight (Left _) = False > > leftToEmpty :: (r -> [a]) -> Either l r -> [a] > leftToEmpty = either (const []) > > replace :: (Eq a) => [a] -> [a] -> [a] -> [a] > replace _ _ [] = [] > replace old new xs@(y:ys) = > case stripPrefix old xs of > Nothing -> y : replace old new ys > Just ys' -> new ++ replace old new ys' > > split :: Char -> String -> [String] > split _ "" = [] > split c s = let (l, s') = break (== c) s > in l : case s' of > [] -> [] > (_:s'') -> split c s'' > > liftThrows :: (MonadError t m) => Either t a -> m a > liftThrows (Left err) = throwError err > liftThrows (Right val) = return val > > -- run in errort monad, throw error as io error > > wrapET :: (Show e, Monad m) => ErrorT e m a -> m a > wrapET c = runErrorT c >>= \x -> > case x of > Left er -> error $ show er > Right l -> return l > > wrapETs :: (Monad m) => ErrorT String m a -> m a > wrapETs c = runErrorT c >>= \x -> > case x of > Left er -> error er > Right l -> return l > > -- error utility - convert either to ErrorT String > > tsl :: (MonadError String m, Show t) => Either t a -> m a > tsl x = case x of > Left s -> throwError $ show s > Right b -> return b > > listEither :: [Either a b] -> Either [a] [b] > listEither es = let (l,r) = partitionEithers es > in if null l > then Right r > else Left l > > forceRight :: Show e => Either e a -> a > forceRight (Left x) = error $ show x > forceRight (Right x) = x > > > npartition :: Eq b => (a -> b) -> [a] -> [(b,[a])] > npartition keyf l = > np [] l > where > np = foldl (\acc p -> insertWith (++) (keyf p) [p] acc) > > insertWith :: Eq k => (a -> a -> a) -> k -> a -> [(k,a)] -> [(k,a)] > insertWith ac k v m = > case lookup k m of > Nothing -> m ++ [(k,v)] > Just v' -> let nv = ac v' v > in map (\p@(k1,_) -> if k1 == k > then (k1,nv) > else p) m This should preserve order, so in the result, the keys (k in [(k,[a],[b])]) are ordered by their first appearance in as, then bs, and the values are ordered the matches in the same order as they appear in the two lists ([a] and [b] in [(k,[a],[b])]) > joinLists :: Eq k => (a -> k) -> (b -> k) > -> [a] -> [b] -> [(k,[a],[b])] > joinLists ka kb as bs = > let -- arrange the two lists by key > kasps = npartition ka as > kbsps = npartition kb bs > -- get the list of keys > ks = nub $ map fst kasps ++ map fst kbsps > -- put together the two lists by key > in flip map ks $ \k -> > (k, getem k kasps, getem k kbsps) > where > getem :: Eq k => k -> [(k,[a])] -> [a] > getem k = concatMap snd . filter ((==k) . fst) > trim :: String -> String > trim = f . f > where f = reverse . dropWhile isSpace > concatLefts :: [Either [a] b] -> Either [a] () > concatLefts s = let l = concat $ lefts s > in if null l > then Right () > else Left l