\subsection{Utility functions} \begin{haskelllisting}
> module Haskore.General.Utility where
>
> import System.Random (randomRs, mkStdGen, )
> import Data.List.HT (segmentBefore, )
> import Data.List (foldl', )
> import Data.Ratio ((%), denominator, numerator, Ratio, )
> import qualified Haskore.General.Map as Map
\end{haskelllisting} \function{splitBy} takes a boolean test and a list; it divides up the list and turns it into a {\em list of sub-lists}; each sub-list consists of \begin{enumerate} \item one element for which the test is true (or the first element in the list), and \item all elements after that element for which the test is false. \end{enumerate} For example, \code{splitBy (>10) [27, 0, 2, 1, 15, 3, 42, 4]} yields \code{[ [27,0,2,1], [15,3], [42,4] ]}. \begin{haskelllisting}
> splitBy :: (a -> Bool) -> [a] -> [[a]]
> splitBy p = dropWhile null . segmentBefore p
\end{haskelllisting} \function{segmentBefore} will have at most one empty list at the beginning, which is dropped by \function{dropWhile}. It should have signature segmentBefore :: (a -> Bool) -> [a] -> ([a], [(a, [a])]) or even better segmentBefore :: (a -> Bool) -> [a] -> AlternatingListUniform.T a [a] and could be implemented using Uniform.fromEitherList A variant of \function{foldr} and \function{foldr1} which works only for non-empty lists and initializes the accumulator depending on the last element of the list. \begin{haskelllisting}
> foldrf :: (a -> b -> b) -> (a -> b) -> [a] -> b
> foldrf f g =
>    let aux []     = error "foldrf: list must be non-empty"
>        aux (x:[]) = g x
>        aux (x:xs) = f x (aux xs)
>    in  aux
\end{haskelllisting} \function{flattenTuples2} flattens a list of pairs into a list. Similarly, \function{flattenTuples3} flattens a list of 3-tuples into a list, and so on. \begin{haskelllisting}
> flattenTuples2 :: [(a,a)]     -> [a]
> flattenTuples3 :: [(a,a,a)]   -> [a]
> flattenTuples4 :: [(a,a,a,a)] -> [a]
>
> flattenTuples2 = concatMap (\(x,y)     -> [x,y])
> flattenTuples3 = concatMap (\(x,y,z)   -> [x,y,z])
> flattenTuples4 = concatMap (\(x,y,z,w) -> [x,y,z,w])
\end{haskelllisting} Variants of \function{zip} and \function{zip3} which check that all argument lists have the same length. \begin{haskelllisting}
> zipWithMatch :: (a -> b -> c) -> [a] -> [b] -> [c]
> zipWithMatch f (x:xs) (y:ys) = f x y : zipWithMatch f xs ys
> zipWithMatch _ [] [] = []
> zipWithMatch _ _ _ = error "zipWithMatch: lengths of lists differ"
> zipWithMatch3 :: (a -> b -> c -> d) -> [a] -> [b] -> [c] -> [d]
> zipWithMatch3 f (x:xs) (y:ys) (z:zs) = f x y z : zipWithMatch3 f xs ys zs
> zipWithMatch3 _ [] [] [] = []
> zipWithMatch3 _ _ _ _ = error "zipWithMatch3: lengths of lists differ"
\end{haskelllisting} This is a variant of \function{maximum} which returns at least zero, i.e. always a non-negative number. This is necessary for determining the length of a parallel music composition where the empty list has zero duration. \begin{haskelllisting}
> maximum0 :: (Ord a, Num a) => [a] -> a
> maximum0 = foldl' max 0
\end{haskelllisting} Convert a mapping (i.e. list of pairs) to a function, and use this for a translation function, which translates every character in a by replacing it by looking it up in l2 and replacing it with the according character in l2. \begin{haskelllisting}
> translate :: (Ord a) => [ a ] -> [ a ] -> [ a ] -> [ a ]
> translate l1 l2 a =
>    if length l1 == length l2
>    then let table = Map.fromList (zip l1 l2)
>         in  map (\x -> Map.findWithDefault table x x) a
>    else error "translate: lists must have equal lengths"
\end{haskelllisting} A random list of integers between 0 and n. \begin{haskelllisting}
> randList :: Int -> [ Int ]
> randList n = randomRs (0, n) (mkStdGen 0)
\end{haskelllisting} Is one rational divisible by another one (i.e., is it a integer multiple of it)? \begin{haskelllisting}
> divisible :: Integral a => Ratio a -> Ratio a -> Bool
> divisible r1 r2 =
>    0 == mod (numerator r1 * denominator r2)
>             (numerator r2 * denominator r1)
\end{haskelllisting} Do the division. \begin{haskelllisting}
> divide :: Integral a => Ratio a -> Ratio a -> a
> divide r1 r2 =
>    let (q, r) = divideModulus r1 r2
>    in  if r == 0
>        then q
>        else error "Utility.divide: rationals are indivisible"
> modulus :: Integral a => Ratio a -> Ratio a -> Ratio a
> modulus r1 r2 = snd (divideModulus r1 r2)
> divideModulus :: Integral a => Ratio a -> Ratio a -> (a, Ratio a)
> divideModulus r1 r2 =
>    let (q, r) = divMod (numerator r1 * denominator r2)
>                        (numerator r2 * denominator r1)
>    in  (q, r % (denominator r1 * denominator r2))
\end{haskelllisting} Also the GCD can be generalized to ratios: \begin{haskelllisting}
> gcdDur :: Integral a => Ratio a -> Ratio a -> Ratio a
> gcdDur x1 x2 =
>    let a = numerator x1
>        b = denominator x1
>        c = numerator x2
>        d = denominator x2
>    in  gcd a c % lcm b d
\end{haskelllisting}