{- | Module : Data.Ratio.Slash Copyright : (c) Jun Narumi 2018 License : BSD3 Maintainer : narumij@gmail.com Stability : experimental Portability : ? Handle fractions described in /, not% -} module Data.Ratio.Slash ( Slash(..), ) where import Control.Monad (guard) import Control.Applicative ((<|>)) import Data.Ratio import Numeric -- | Type of read and show slash form rational -- -- >>> getRatio . read $ "1/2" -- 1 % 2 -- -- >>> map getRatio . read $ "[1/2,3/4,5/6]" -- [1 % 2,3 % 4,5 % 6] -- -- >>> Slash (1 % 2) -- 1/2 -- -- >>> map Slash [1%2,3%4,5%6] -- [1/2,3/4,5/6] -- newtype Slash a = Slash { getRatio :: Ratio a } deriving (Eq,Ord) instance (Integral a) => Show (Slash a) where showsPrec _ (Slash n) | denominator n == 1 = showSigned showInt 0 (numerator n) | otherwise = showSigned showInt 0 (numerator n) . showString "/" . showInt (denominator n) instance (Integral a) => Read (Slash a) where readsPrec _ n = do ( ( n, d ), st ) <- slashOrInteger n guard $ d /= 0 return ( Slash $ n % d , st ) integer :: (Integral a) => ReadS (a,a) integer n = do ( n, st ) <- readSigned readDec n return ( ( n, 1 ), st ) slash :: (Integral a) => ReadS (a,a) slash n = do ( numer, st ) <- readSigned readDec n ( "/" , st1 ) <- lex st ( denom, st2 ) <- readDec st1 return ( ( numer, denom ), st2) slashOrInteger :: (Integral a) => ReadS (a,a) slashOrInteger n = take 1 $ slash n <|> integer n