{-# LANGUAGE CPP #-}
{-# LANGUAGE UnicodeSyntax #-}
{-# LANGUAGE DeriveDataTypeable #-}
#if __GLASGOW_HASKELL__ >= 706
{-# LANGUAGE DeriveGeneric #-}
#endif

-- | Print fractions.
module Text.Printer.Fractional
  (
  -- * Positional numeral systems
    PositionalSystem(..)
  , BitSystem(..)
  , Binary(..)
  , Octal(..)
  , Decimal(..)
  , Hexadecimal(..)
  , LowHex(..)
  , UpHex(..)
  -- * Optionality characteristic
  , Optional(..)
  , isOptional
  , isRequired
  -- * Fraction printers
  , fraction'
  , fraction
  ) where

#if __GLASGOW_HASKELL__ >= 706
import GHC.Generics (Generic)
#endif
import Data.Typeable (Typeable)
import Data.Ix (Ix)
import Data.Monoid (mempty)
import Data.Ratio (numerator, denominator)
import Text.Printer
import Text.Printer.Integral

-- | Optionality characteristic.
data Optional = Optional
              | Required
              deriving ( Typeable
#if __GLASGOW_HASKELL__ >= 706
                       , (forall x. Optional -> Rep Optional x)
-> (forall x. Rep Optional x -> Optional) -> Generic Optional
forall x. Rep Optional x -> Optional
forall x. Optional -> Rep Optional x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Optional x -> Optional
$cfrom :: forall x. Optional -> Rep Optional x
Generic
#endif
                       , Int -> Optional -> ShowS
[Optional] -> ShowS
Optional -> String
(Int -> Optional -> ShowS)
-> (Optional -> String) -> ([Optional] -> ShowS) -> Show Optional
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Optional] -> ShowS
$cshowList :: [Optional] -> ShowS
show :: Optional -> String
$cshow :: Optional -> String
showsPrec :: Int -> Optional -> ShowS
$cshowsPrec :: Int -> Optional -> ShowS
Show, ReadPrec [Optional]
ReadPrec Optional
Int -> ReadS Optional
ReadS [Optional]
(Int -> ReadS Optional)
-> ReadS [Optional]
-> ReadPrec Optional
-> ReadPrec [Optional]
-> Read Optional
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [Optional]
$creadListPrec :: ReadPrec [Optional]
readPrec :: ReadPrec Optional
$creadPrec :: ReadPrec Optional
readList :: ReadS [Optional]
$creadList :: ReadS [Optional]
readsPrec :: Int -> ReadS Optional
$creadsPrec :: Int -> ReadS Optional
Read, Optional -> Optional -> Bool
(Optional -> Optional -> Bool)
-> (Optional -> Optional -> Bool) -> Eq Optional
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Optional -> Optional -> Bool
$c/= :: Optional -> Optional -> Bool
== :: Optional -> Optional -> Bool
$c== :: Optional -> Optional -> Bool
Eq, Eq Optional
Eq Optional
-> (Optional -> Optional -> Ordering)
-> (Optional -> Optional -> Bool)
-> (Optional -> Optional -> Bool)
-> (Optional -> Optional -> Bool)
-> (Optional -> Optional -> Bool)
-> (Optional -> Optional -> Optional)
-> (Optional -> Optional -> Optional)
-> Ord Optional
Optional -> Optional -> Bool
Optional -> Optional -> Ordering
Optional -> Optional -> Optional
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Optional -> Optional -> Optional
$cmin :: Optional -> Optional -> Optional
max :: Optional -> Optional -> Optional
$cmax :: Optional -> Optional -> Optional
>= :: Optional -> Optional -> Bool
$c>= :: Optional -> Optional -> Bool
> :: Optional -> Optional -> Bool
$c> :: Optional -> Optional -> Bool
<= :: Optional -> Optional -> Bool
$c<= :: Optional -> Optional -> Bool
< :: Optional -> Optional -> Bool
$c< :: Optional -> Optional -> Bool
compare :: Optional -> Optional -> Ordering
$ccompare :: Optional -> Optional -> Ordering
$cp1Ord :: Eq Optional
Ord, Int -> Optional
Optional -> Int
Optional -> [Optional]
Optional -> Optional
Optional -> Optional -> [Optional]
Optional -> Optional -> Optional -> [Optional]
(Optional -> Optional)
-> (Optional -> Optional)
-> (Int -> Optional)
-> (Optional -> Int)
-> (Optional -> [Optional])
-> (Optional -> Optional -> [Optional])
-> (Optional -> Optional -> [Optional])
-> (Optional -> Optional -> Optional -> [Optional])
-> Enum Optional
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: Optional -> Optional -> Optional -> [Optional]
$cenumFromThenTo :: Optional -> Optional -> Optional -> [Optional]
enumFromTo :: Optional -> Optional -> [Optional]
$cenumFromTo :: Optional -> Optional -> [Optional]
enumFromThen :: Optional -> Optional -> [Optional]
$cenumFromThen :: Optional -> Optional -> [Optional]
enumFrom :: Optional -> [Optional]
$cenumFrom :: Optional -> [Optional]
fromEnum :: Optional -> Int
$cfromEnum :: Optional -> Int
toEnum :: Int -> Optional
$ctoEnum :: Int -> Optional
pred :: Optional -> Optional
$cpred :: Optional -> Optional
succ :: Optional -> Optional
$csucc :: Optional -> Optional
Enum, Optional
Optional -> Optional -> Bounded Optional
forall a. a -> a -> Bounded a
maxBound :: Optional
$cmaxBound :: Optional
minBound :: Optional
$cminBound :: Optional
Bounded, Ord Optional
Ord Optional
-> ((Optional, Optional) -> [Optional])
-> ((Optional, Optional) -> Optional -> Int)
-> ((Optional, Optional) -> Optional -> Int)
-> ((Optional, Optional) -> Optional -> Bool)
-> ((Optional, Optional) -> Int)
-> ((Optional, Optional) -> Int)
-> Ix Optional
(Optional, Optional) -> Int
(Optional, Optional) -> [Optional]
(Optional, Optional) -> Optional -> Bool
(Optional, Optional) -> Optional -> Int
forall a.
Ord a
-> ((a, a) -> [a])
-> ((a, a) -> a -> Int)
-> ((a, a) -> a -> Int)
-> ((a, a) -> a -> Bool)
-> ((a, a) -> Int)
-> ((a, a) -> Int)
-> Ix a
unsafeRangeSize :: (Optional, Optional) -> Int
$cunsafeRangeSize :: (Optional, Optional) -> Int
rangeSize :: (Optional, Optional) -> Int
$crangeSize :: (Optional, Optional) -> Int
inRange :: (Optional, Optional) -> Optional -> Bool
$cinRange :: (Optional, Optional) -> Optional -> Bool
unsafeIndex :: (Optional, Optional) -> Optional -> Int
$cunsafeIndex :: (Optional, Optional) -> Optional -> Int
index :: (Optional, Optional) -> Optional -> Int
$cindex :: (Optional, Optional) -> Optional -> Int
range :: (Optional, Optional) -> [Optional]
$crange :: (Optional, Optional) -> [Optional]
$cp1Ix :: Ord Optional
Ix)

-- | True if the supplied value is 'Optional' and false otherwise.
isOptional  Optional  Bool
isOptional :: Optional -> Bool
isOptional Optional
Optional = Bool
True
isOptional Optional
Required = Bool
False

-- | True if the supplied value is 'Required' and false otherwise.
isRequired  Optional  Bool
isRequired :: Optional -> Bool
isRequired Optional
Optional = Bool
False
isRequired Optional
Required = Bool
True

-- | Print a fraction, writing the numerator and the denominator in
--   the specified positional numeral system.
fraction'  (PositionalSystem s, Real α, Printer p)
           s
           p -- ^ Prefix for negative values
           p -- ^ Zero printer
           p -- ^ Prefix for positive values
           p -- ^ Numerator/denominator separator
           Optional -- ^ Whether to print invisible denominators
           α  p
fraction' :: s -> p -> p -> p -> p -> Optional -> α -> p
fraction' s
s p
neg p
z p
pos p
sep Optional
i α
a
    | Integer
n Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
0    = p
z
    | Integer
d Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
1    = case Optional
i of
                    Optional
Optional  s -> p -> p -> p -> Integer -> p
forall s α p.
(PositionalSystem s, Integral α, Printer p) =>
s -> p -> p -> p -> α -> p
number' s
s p
neg p
z p
pos Integer
n
                    Optional
Required   s -> p -> p -> p -> Integer -> p
forall s α p.
(PositionalSystem s, Integral α, Printer p) =>
s -> p -> p -> p -> α -> p
number' s
s p
neg p
z p
pos Integer
n
                             p -> p -> p
forall a. Semigroup a => a -> a -> a
<> p
sep
                             p -> p -> p
forall a. Semigroup a => a -> a -> a
<> (s -> Char -> p
forall s p. (PositionalSystem s, Printer p) => s -> Char -> p
printDigitIn s
s (Char -> p) -> Char -> p
forall a b. (a -> b) -> a -> b
$! s -> Int -> Char
forall s. PositionalSystem s => s -> Int -> Char
intToDigitIn s
s Int
1)
    | Bool
otherwise = if Integer
n Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
< Integer
0
                  then p
neg p -> p -> p
forall a. Semigroup a => a -> a -> a
<> s -> Integer -> p
forall s α p.
(PositionalSystem s, Integral α, Printer p) =>
s -> α -> p
nonPositive s
s Integer
n p -> p -> p
forall a. Semigroup a => a -> a -> a
<> p
sep p -> p -> p
forall a. Semigroup a => a -> a -> a
<> s -> Integer -> p
forall s α p.
(PositionalSystem s, Integral α, Printer p) =>
s -> α -> p
nonNegative s
s Integer
d
                  else p
pos p -> p -> p
forall a. Semigroup a => a -> a -> a
<> s -> Integer -> p
forall s α p.
(PositionalSystem s, Integral α, Printer p) =>
s -> α -> p
nonNegative s
s Integer
n p -> p -> p
forall a. Semigroup a => a -> a -> a
<> p
sep p -> p -> p
forall a. Semigroup a => a -> a -> a
<> s -> Integer -> p
forall s α p.
(PositionalSystem s, Integral α, Printer p) =>
s -> α -> p
nonNegative s
s Integer
d
  where r :: Rational
r = α -> Rational
forall a. Real a => a -> Rational
toRational α
a
        n :: Integer
n = Rational -> Integer
forall a. Ratio a -> a
numerator Rational
r
        d :: Integer
d = Rational -> Integer
forall a. Ratio a -> a
denominator Rational
r

-- | Print a fraction. The numerator and the denominator are written in the
--   decimal numeral system and separated by a slash. Negative values
--   are prefixed with a minus sign. Invisible denominators are omitted.
fraction  (Real α, Printer p)  α  p
fraction :: α -> p
fraction = Decimal -> p -> p -> p -> p -> Optional -> α -> p
forall s α p.
(PositionalSystem s, Real α, Printer p) =>
s -> p -> p -> p -> p -> Optional -> α -> p
fraction' Decimal
Decimal (Char -> p
forall p. Printer p => Char -> p
char7 Char
'-') (Char -> p
forall p. Printer p => Char -> p
char7 Char
'0')
                     p
forall a. Monoid a => a
mempty (Char -> p
forall p. Printer p => Char -> p
char7 Char
'/') Optional
Optional