module Helpers(maybeHead,
               headOrElse,
               statefully,
               mapTuple,
               statefullyTakeWhile,
               histogram) where

import Data.Maybe
import qualified Data.Map as Map

maybeHead :: [a] -> Maybe a
maybeHead []     = Nothing
maybeHead (x:xs) = Just x

headOrElse :: a -> [a] -> a
headOrElse d ls = fromMaybe d (maybeHead ls)

statefully :: (g -> (a, g)) -> Int -> g -> ([a], g)
statefully f n g0 = case n of
    0 -> ([], g0)
    x -> (r:rest, g2)
      where
        (r, g1) = f g0
        (rest, g2) = statefully f (n-1) g1

statefullyTakeWhile :: (g -> (a, g)) ->
                       ([a] -> Bool) ->
                       g ->
                       ([a], g)
statefullyTakeWhile f p g0 = r ([], g0)
  where
    r (list, g1)
      | p list    = (list, g1)
      | otherwise = mapTuple (\l -> l:list) (id) (f g1)


mapTuple :: (a -> b) -> (c -> d) -> (a, c) -> (b, d)    
mapTuple f g (x, y) = (f x, g y)

histogram :: Double -> [Double] -> [Int]
histogram precision ls = map lookup0 [0..limit]
  where
    limit = truncate $ (1.0 / precision)
    divs = map (\x -> x / precision) ls
    ints = map (truncate) divs
    m   = foldl
          (\b a ->
            Map.insert a ((fromMaybe 0 (Map.lookup a b))+1) b)
          Map.empty
          ints
    lookup0 = (\x -> fromMaybe 0 $ Map.lookup x m)
    
toDbl = fromInteger . toInteger