```{- |
Number type based on Float with formatting in percents.
-}
module Numeric.Probability.Percentage where

import qualified Numeric.Probability.Distribution as Dist
import qualified Numeric.Probability.Random as Rnd

import Numeric.Probability.Show (showR)
import Numeric.Probability.Trace (Trace)

import qualified System.Random as Random

-- ** Probabilities
newtype T = Cons Float
deriving (Eq, Ord)

percent :: Float -> T
percent x = Cons (x/100)

showPfix :: (RealFrac prob, Show prob) => Int -> prob -> String
showPfix precision x =
if precision==0
then showR 3 (round (x*100) :: Integer) ++ "%"
else
let str =
(show (round (x*10^(precision+2)) :: Integer))
(int,frac) =
splitAt (length str - precision) str
in  padLeft ' ' 3 int ++ '.' : frac ++ "%"

{-# DEPRECATED roundRel "was used to implemented showPfix, but is no longer needed for this purpose, and should not be exported anyway, and does not contribute to a safe way to format fixed point values, because the rounded value may not be accurate" #-}
roundRel :: (RealFrac a) => Int -> a -> a
roundRel p x =
let d = 10^p
in  fromIntegral (round (x*d) :: Integer)/d

-- -- mixed precision
-- --
-- showP :: ProbRep -> String
-- showP f | f>=0.1    = showR 3 (round (f*100))++"%"
--         | otherwise = show (f*100)++"%"

-- fixed precision
--
-- showP :: ProbRep -> String
-- showP = showPfix 1

instance Show T where
show (Cons p) = showPfix 1 p

infix 0 //

{- |
Print distribution as table with configurable precision.
-}
(//) :: (Ord a, Show a) => Dist a -> Int -> IO ()
(//) x prec = putStr (Dist.pretty (\(Cons p) -> showPfix prec p) x)

(//*) :: (Ord a, Show a) => Dist a -> (Int,Int) -> IO ()
(//*) x (prec,width) = putStr \$ flip Dist.pretty x \$
\(Cons p) ->
showPfix prec p ++ " " ++
replicate (round (p * fromIntegral width)) '*'

liftP :: (Float -> Float) -> T -> T
liftP f (Cons x) = Cons (f x)

liftP2 :: (Float -> Float -> Float) -> T -> T -> T
liftP2 f (Cons x) (Cons y) = Cons (f x y)

instance Num T where
fromInteger = Cons . fromInteger
(+) = liftP2 (+)
(-) = liftP2 (-)
(*) = liftP2 (*)
abs = liftP abs
signum = liftP signum
negate = liftP negate

instance Fractional T where
fromRational = Cons . fromRational
recip = liftP recip
(/) = liftP2 (/)

instance Floating T where
pi = Cons pi
exp = liftP exp
sqrt = liftP sqrt
log = liftP log
(**) = liftP2 (**)
logBase = liftP2 logBase
sin = liftP sin
tan = liftP tan
cos = liftP cos
asin = liftP asin
atan = liftP atan
acos = liftP acos
sinh = liftP sinh
tanh = liftP tanh
cosh = liftP cosh
asinh = liftP asinh
atanh = liftP atanh
acosh = liftP acosh

instance Random.Random T where
randomR (Cons l, Cons r) =
(\(x,g) -> (Cons x, g)) . Random.randomR (l,r)
random =
(\(x,g) -> (Cons x, g)) . Random.random
randomRIO (Cons l, Cons r) = fmap Cons \$ Random.randomRIO (l,r)
randomIO = fmap Cons \$ Random.randomIO

type Dist a = Dist.T T a

type Spread a = [a] -> Dist a

type RDist a = Rnd.T (Dist a)

type Trans a = a -> Dist a

type Space a  = Trace (Dist a)
type Expand a = a -> Space a

type RTrans a = a -> RDist a

type RSpace a  = Rnd.T (Space a)
type RExpand a = a -> RSpace a
```