Created
January 26, 2018 01:29
-
-
Save adituv/5486a7f6aebbf3945b604d6304cc1366 to your computer and use it in GitHub Desktop.
Show ratios as a mixed fraction
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-# LANGUAGE MultiWayIf #-} | |
{-# LANGUAGE PatternSynonyms #-} | |
{-# LANGUAGE ViewPatterns #-} | |
module Text.Show.Ratio(showMixed, showsMixed, showsPrecMixed) where | |
import Data.Ratio | |
-- | Convert a @'Ratio' a@ to a readable string, where the ratio is | |
-- expressed as a mixed fraction in its simplest form. `showsPrecMixed` | |
-- is designed for use as part of another show implementation, and so | |
-- adds parentheses when the operator precedence of the enclosing context | |
-- is greater than that of '+' (a value of 6) | |
showsPrecMixed :: (Show a, Integral a) | |
=> Int -- ^ the operator precedence of the enclosing context | |
-- (a number from @0@ to @11@). Function application has | |
-- precedence @10@ | |
-> Ratio a -- ^ The ratio to be converted to a 'String' | |
-> ShowS | |
showsPrecMixed p x = showParen (p > 6) $ showsMixed x | |
-- | Convert a @'Ratio' a@ to a readable string, where the ratio is | |
-- expressed as a mixed fraction in its simplest form | |
showsMixed :: (Show a, Integral a) => Ratio a -> ShowS | |
showsMixed (n :% d) = quotStr . showString op . remStr | |
where | |
(q,r) = n `quotRem` d | |
op = if q /= 0 && r > 0 -- Three cases where q /= 0: | |
then "+" -- * r > 0: show r does not include its sign | |
else "" -- * r < 0: show r includes its sign. | |
-- * r == 0: r will be excluded from the output | |
quotStr = if | q == 0 && r == 0 -> showString "0" | |
| q == 0 -> id | |
| otherwise -> shows q | |
remStr = if r == 0 | |
then id | |
else shows r . showString "/" . shows d | |
-- NB @showString "" === (""++) === id@. It would probably be optimised out | |
-- correctly but I used @id@ instead of @showString ""@ just to be sure | |
-- | Convert a @'Ratio' a@ to a readable string, where the ratio is | |
-- expressed as a mixed fraction in its simplest form | |
showMixed :: (Show a, Integral a) => Ratio a -> String | |
showMixed = flip showsMixed "" | |
-- Utility pattern as the constructor of Ratio is not exposed | |
pattern n :% d <- (splitRatio -> (n,d)) | |
splitRatio :: Ratio a -> (a,a) | |
splitRatio x = (numerator x, denominator x) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment