```
module Language.CalDims.Helpers
( F
, again
, third
, unlines'
, logBaseInt
, (#&&#)
, combination
, permutation
, if_ -- functional if
, ErrorAndState
, eqClassesWith
) where

type ErrorAndState e s a = ErrorT e (State s) a
type F = Double

unlines' :: [String] -> String
unlines' [] = ""
unlines' [a] = a
unlines' (a:as) = a ++ "\n" ++ unlines' as

logBaseInt :: Integral a => a -> a -> Maybe a
logBaseInt a b = if a ^ res == b then Just res else Nothing
where
res = round (logBase (fromIntegral a) (fromIntegral b) :: Double)

again :: Monad m => (a -> m b) -> [a] -> m ()
again _ [] = return ()
again f (x:xs) = f x >> again f xs

headWithDefault ::  a -> [a] -> a

(#&&#) :: Monad m => m Bool -> m Bool -> m Bool
(#&&#) = liftM2 (&&)

third :: (a, b, c) -> c
third (_, _, c) = c

--tc :: Eq a => (a -> [a]) -> a -> [a]
--tc f start = start : concatMap (tc f) (filter (/= start) \$ f start)

if_ :: Bool -> a -> a -> a
if_ True a _ = a
if_ False _ b = b

eqClassesWith :: (a -> a -> Bool) -> [a] -> [(a,[a])]
eqClassesWith f l = foldl (ff f) [] l

ff :: (a -> a -> Bool) -> [(a, [a])] -> a -> [(a, [a])]
ff _ [] a = [(a, [])]
ff f ((r,rs):on) a = if f r a then ((r,(a:rs)):on) else (r,rs):(ff f on a)

-- combination i l lists all combinations (without repetitions) of set l of order i
-- example:
-- ["abc","abd","acd","bcd"]

combination :: Int -> [a] -> [[a]]
combination i l
| i > length l = error "i > len l"
| i == 1 = map (\x -> [x]) l
| null l = []
| i == length l = [l]
| otherwise = let (a:as) = l in
zipWith (:) (repeat a) (combination (i - 1) as) ++ combination i as

permutation :: Int -> [a] -> [[a]]
permutation i l
| i < 1 = error "i > len l"
| i == 1 = map (\x -> [x]) l
| otherwise = [ x:y | x <- l, y <- (permutation (i - 1) l)]
```