{-# OPTIONS_GHC -Wall #-}
-----------------------------------------------------------------------------
-- |
-- Module      :  ToySolver.Internal.Util
-- Copyright   :  (c) Masahiro Sakai 2011-2012
-- License     :  BSD-style
--
-- Maintainer  :  masahiro.sakai@gmail.com
-- Stability   :  provisional
-- Portability :  portable
--
-- Some utility functions.
--
-----------------------------------------------------------------------------

module ToySolver.Internal.Util where

import Control.Monad
import Data.Ratio
import Data.Set (Set)
import qualified Data.Set as Set
import System.IO
import GHC.IO.Encoding

-- | Combining two @Maybe@ values using given function.
combineMaybe :: (a -> a -> a) -> Maybe a -> Maybe a -> Maybe a
combineMaybe :: forall a. (a -> a -> a) -> Maybe a -> Maybe a -> Maybe a
combineMaybe a -> a -> a
_ Maybe a
Nothing Maybe a
y = Maybe a
y
combineMaybe a -> a -> a
_ Maybe a
x Maybe a
Nothing = Maybe a
x
combineMaybe a -> a -> a
f (Just a
x) (Just a
y) = forall a. a -> Maybe a
Just (a -> a -> a
f a
x a
y)

-- | is the number integral?
--
-- @
--    isInteger x = fromInteger (round x) == x
-- @
isInteger :: RealFrac a => a -> Bool
isInteger :: forall a. RealFrac a => a -> Bool
isInteger a
x = forall a. Num a => Integer -> a
fromInteger (forall a b. (RealFrac a, Integral b) => a -> b
round a
x) forall a. Eq a => a -> a -> Bool
== a
x

-- | fractional part
--
-- @
--   fracPart x = x - fromInteger (floor x)
-- @
fracPart :: RealFrac a => a -> a
fracPart :: forall a. RealFrac a => a -> a
fracPart a
x = a
x forall a. Num a => a -> a -> a
- forall a. Num a => Integer -> a
fromInteger (forall a b. (RealFrac a, Integral b) => a -> b
floor a
x)

showRational :: Bool -> Rational -> String
showRational :: Bool -> Rational -> String
showRational Bool
asRatio Rational
v
  | forall a. Ratio a -> a
denominator Rational
v forall a. Eq a => a -> a -> Bool
== Integer
1 = forall a. Show a => a -> String
show (forall a. Ratio a -> a
numerator Rational
v)
  | Bool
asRatio            = forall a. Show a => a -> String
show (forall a. Ratio a -> a
numerator Rational
v) forall a. [a] -> [a] -> [a]
++ String
"/" forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show (forall a. Ratio a -> a
denominator Rational
v)
  | Bool
otherwise          = forall a. Show a => a -> String
show (forall a. Fractional a => Rational -> a
fromRational Rational
v :: Double)

showRationalAsFiniteDecimal :: Rational -> Maybe String
showRationalAsFiniteDecimal :: Rational -> Maybe String
showRationalAsFiniteDecimal Rational
x = do
  let a :: Integer
      (Integer
a,Rational
b) = forall a b. (RealFrac a, Integral b) => a -> (b, a)
properFraction (forall a. Num a => a -> a
abs Rational
x)
      s1 :: String
s1 = if Rational
x forall a. Ord a => a -> a -> Bool
< Rational
0 then String
"-" else String
""
      s2 :: String
s2 = forall a. Show a => a -> String
show Integer
a
  String
s3 <- if Rational
b forall a. Eq a => a -> a -> Bool
== Rational
0
        then forall (m :: * -> *) a. Monad m => a -> m a
return String
".0"
        else forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM (String
"." forall a. [a] -> [a] -> [a]
++ ) forall a b. (a -> b) -> a -> b
$ Set Rational -> Rational -> Maybe String
loop forall a. Set a
Set.empty Rational
b
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ String
s1 forall a. [a] -> [a] -> [a]
++ String
s2 forall a. [a] -> [a] -> [a]
++ String
s3
  where
    loop :: Set Rational -> Rational -> Maybe String
    loop :: Set Rational -> Rational -> Maybe String
loop Set Rational
_ Rational
0 = forall (m :: * -> *) a. Monad m => a -> m a
return String
""
    loop Set Rational
rs Rational
r
      | Rational
r forall a. Ord a => a -> Set a -> Bool
`Set.member` Set Rational
rs = forall (m :: * -> *) a. MonadPlus m => m a
mzero
      | Bool
otherwise = do
          let a :: Integer
              (Integer
a,Rational
b) = forall a b. (RealFrac a, Integral b) => a -> (b, a)
properFraction (Rational
r forall a. Num a => a -> a -> a
* Rational
10)
          String
s <- Set Rational -> Rational -> Maybe String
loop (forall a. Ord a => a -> Set a -> Set a
Set.insert Rational
r Set Rational
rs) Rational
b
          forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a. Show a => a -> String
show Integer
a forall a. [a] -> [a] -> [a]
++ String
s

{-# INLINE revSequence #-}
revSequence :: Monad m => [m a] -> m [a]
revSequence :: forall (m :: * -> *) a. Monad m => [m a] -> m [a]
revSequence = forall {m :: * -> *} {a}. Monad m => [a] -> [m a] -> m [a]
go []
  where
    go :: [a] -> [m a] -> m [a]
go [a]
xs [] = forall (m :: * -> *) a. Monad m => a -> m a
return [a]
xs
    go [a]
xs (m a
m:[m a]
ms) = do
      a
x <- m a
m
      [a] -> [m a] -> m [a]
go (a
xforall a. a -> [a] -> [a]
:[a]
xs) [m a]
ms

{-# INLINE revMapM #-}
revMapM :: Monad m => (a -> m b) -> ([a] -> m [b])
revMapM :: forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
revMapM a -> m b
f = forall (m :: * -> *) a. Monad m => [m a] -> m [a]
revSequence forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map a -> m b
f

{-# INLINE revForM #-}
revForM :: Monad m => [a] -> (a -> m b) -> m [b]
revForM :: forall (m :: * -> *) a b. Monad m => [a] -> (a -> m b) -> m [b]
revForM = forall a b c. (a -> b -> c) -> b -> a -> c
flip forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
revMapM

setEncodingChar8 :: IO ()
setEncodingChar8 :: IO ()
setEncodingChar8 = do
  TextEncoding -> IO ()
setLocaleEncoding TextEncoding
char8
  TextEncoding -> IO ()
setForeignEncoding TextEncoding
char8
  TextEncoding -> IO ()
setFileSystemEncoding TextEncoding
char8