content: 
  This file contains some generic utility stuff
  
  > {-# LANGUAGE TupleSections #-}
  > {-# LANGUAGE FlexibleContexts #-}
  > module Database.HsSqlPpp.Internals.Utils where
  >
  > import Control.Arrow
  > import Control.Applicative
  > import Data.List
  > import Data.Char
  
  > infixl 9 |>
  > (|>) :: (a -> b) -> (b -> c) -> a -> c
  > (|>) = flip (.)
  >
  > both :: (a->b) -> (a,a) -> (b,b)
  > both fn = fn *** fn
  >
  > (<:>) :: (Applicative f) =>
  >          f a -> f [a] -> f [a]
  > (<:>) a b = (:) <$> a <*> b
  
  > firstM :: Functor f => (t -> f a) -> (t, t1) -> f (a, t1)
  > firstM f (a,b) = (,b) <$> f a
  
  > secondM :: Functor f => (t -> f a) -> (t1, t) -> f (t1, a)
  > secondM f (a,b) = (a,) <$> f b
  
  > 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''
  >
  > npartition :: Eq b => (a -> b) -> [a] -> [(b,[a])]
  > npartition keyf =
  >   np []
  >   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
  