module Wumpus.Core.Utils
(
CMinMax(..)
, within
, max3
, min3
, med3
, PSUnit(..)
, truncateDouble
, roundup
, rescale
, clamp
, ramp
, ramp255
, mkTimeStamp
, parens
, hsep
, commasep
, tupled
, sequenceA
, (<:>)
, H
, toListH
, OneList(..)
, mkList2
, onesmapM_
, toListWith
, toListWithM
, fromListErr
, appro
, oo
, ooo
, oooo
, rap
) where
import Control.Applicative
import Control.Monad ( ap )
import Data.List ( intersperse )
import Data.Ratio
import Data.Time
class CMinMax a where
cmin :: a -> a -> a
cmax :: a -> a -> a
instance (Ord a, Ord b) => CMinMax (a,b) where
cmin (x,y) (x',y') = (min x x', min y y')
cmax (x,y) (x',y') = (max x x', max y y')
within :: Eq a => CMinMax a => a -> a -> a -> Bool
within a lower upper = (cmin a lower) == lower && (cmax a upper) == upper
max3 :: Ord a => a -> a -> a -> a
max3 a b c = max (max a b) c
min3 :: Ord a => a -> a -> a -> a
min3 a b c = min (min a b) c
med3 :: Ord a => a -> a -> a -> a
med3 a b c = if c <= x then x else if c > y then y else c
where
(x,y) = order a b
order p q | p <= q = (p,q)
| otherwise = (q,p)
class Num a => PSUnit a where
toDouble :: a -> Double
dtrunc :: a -> String
dtrunc = truncateDouble . toDouble
instance PSUnit Double where
toDouble = id
dtrunc = truncateDouble
instance PSUnit Float where
toDouble = realToFrac
instance PSUnit (Ratio Integer) where
toDouble = realToFrac
instance PSUnit (Ratio Int) where
toDouble = realToFrac
truncateDouble :: Double -> String
truncateDouble d | abs d < 0.0001 = "0.0"
| d < 0.0 = '-' : show (abs tx)
| otherwise = show tx
where
tx :: Double
tx = (realToFrac (roundi (d*1000000.0))) / 1000000.0
roundi :: RealFrac a => a -> Integer
roundi = round
roundup :: Double -> String
roundup = show . ceilingi
ceilingi :: RealFrac a => a -> Integer
ceilingi = ceiling
rescale :: Fractional a => (a,a) -> (a,a) -> a -> a
rescale (amin,amax) (bmin,bmax) a =
bmin + apos * (brange / arange)
where
arange = amax amin
brange = bmax bmin
apos = a amin
clamp :: Ord a => a -> a -> a -> a
clamp amin amax x = max amin (min amax x)
ramp :: Double -> Double
ramp = clamp 0 1
ramp255 :: Double -> Int
ramp255 = clamp 0 255 . ceiling . (*255)
mkTimeStamp :: IO String
mkTimeStamp = getZonedTime >>= return . format . zonedTimeToLocalTime
where
format t = mkTime t ++ " " ++ mkDate t
mkTime = concat . intersperse ":" . sequenceA tfuns . localTimeOfDay
mkDate = showGregorian . localDay
tfuns = [ pad2 . todHour, pad2 . todMin, pad2 . floori . todSec ]
pad2 i | i < 10 = '0' : show i
| otherwise = show i
floori :: RealFrac a => a -> Int
floori = floor
parens :: String -> String
parens s = "(" ++ s ++ ")"
hsep :: [String] -> String
hsep = concat . intersperse " "
commasep :: [String] -> String
commasep = concat . intersperse ","
tupled :: [String] -> String
tupled = parens . concat . intersperse ", "
sequenceA :: Applicative f => [f a] -> f [a]
sequenceA = foldr (<:>) (pure [])
infixr 6 <:>
(<:>) :: Applicative f => f a -> f [a] -> f [a]
(<:>) a b = (:) <$> a <*> b
type H a = [a] -> [a]
toListH :: H a -> [a]
toListH = ($ [])
infixr 5 `Many`
data OneList a = One a | Many a (OneList a)
deriving (Eq)
instance Show a => Show (OneList a) where
show = ('{':) . ($ []) . step where
step (One a) = shows a . showChar '}'
step (Many a xs) = shows a . showChar ',' . step xs
mkList2 :: a -> a -> OneList a
mkList2 a b = a `Many` One b
onesmapM_ :: Monad m => (a -> m b) -> OneList a -> m ()
onesmapM_ f (One x) = f x >> return ()
onesmapM_ f (Many x xs) = f x >> onesmapM_ f xs
toListWith :: (a -> b) -> OneList a -> [b]
toListWith f (One x) = [f x]
toListWith f (Many x xs) = f x : toListWith f xs
toListWithM :: Monad m => (a -> m b) -> OneList a -> m [b]
toListWithM mf (One x) = mf x >>= \a -> return [a]
toListWithM mf (Many x xs) = return (:) `ap` mf x `ap` toListWithM mf xs
fromListErr :: [a] -> String -> OneList a
fromListErr xs0 msg = step xs0 where
step [] = error msg
step [a] = One a
step (a:xs) = Many a $ step xs
appro :: (c -> d -> e) -> (a -> c) -> (b -> d) -> a -> b -> e
appro comb f g x y = comb (f x) (g y)
oo :: (c -> d) -> (a -> b -> c) -> a -> b -> d
oo f g = (f .) . g
ooo :: (d -> e) -> (a -> b -> c -> d) -> a -> b -> c -> e
ooo f g = ((f .) .) . g
oooo :: (e -> f) -> (a -> b -> c -> d -> e) -> a -> b -> c -> d -> f
oooo f g = (((f .) .) .) . g
infixl 1 `rap`
rap :: a -> (a -> b) -> b
rap a f = f a