Created
March 29, 2014 17:50
-
-
Save pxqr/9858955 to your computer and use it in GitHub Desktop.
parsing and pretty printing of some quantities with units by introducing newtype wrappers. Despite of pretty printing, Read/Show instances obey standart rules. This might be useful in some CLI programs and options parsing.
This file contains hidden or 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
-- SI binary prefixes of positive power. | |
-- | |
-- > http://physics.nist.gov/cuu/Units/binary.html | |
-- | |
{-# LANGUAGE Safe #-} | |
module Data.Unit.Bin | |
( Unit(..) | |
, prefix, fromPrefix, multiplier | |
, unit, formatS | |
) where | |
import Control.Applicative | |
import Data.Maybe | |
import Data.Word | |
import qualified Data.Unit.Dec as U10 | |
data Unit | |
= Kibi -- ^ 2 ^ 10 | |
| Mebi -- ^ 2 ^ 20 | |
| Gibi -- ^ 2 ^ 30 | |
| Tebi -- ^ 2 ^ 40 | |
| Pebi -- ^ 2 ^ 50 | |
| Exbi -- ^ 2 ^ 60 | |
| Zebi -- ^ 2 ^ 70 | |
| Yobi -- ^ 2 ^ 80 | |
deriving (Show, Read, Eq, Ord, Bounded, Enum) | |
convert :: (Enum a, Enum b) => a -> b | |
convert = toEnum . fromEnum | |
prefix :: Unit -> String | |
prefix u = (: "i") $ fromJust $ lookup (convert u) U10.table | |
fromPrefix :: String -> Maybe Unit | |
fromPrefix (c : 'i' : []) = convert <$> U10.fromPrefix c | |
fromPrefix _ = Nothing | |
multiplier :: Num a => Unit -> a | |
multiplier u = 2 ^ (10 * (succ (fromEnum u))) | |
unit :: (Ord a, Num a) => a -> Maybe Unit | |
unit x | x < 2 ^ (10 :: Word) = Nothing | |
| x < 2 ^ (20 :: Word) = Just Kibi | |
| x < 2 ^ (30 :: Word) = Just Mebi | |
| x < 2 ^ (40 :: Word) = Just Gibi | |
| x < 2 ^ (50 :: Word) = Just Tebi | |
| x < 2 ^ (60 :: Word) = Just Pebi | |
| x < 2 ^ (70 :: Word) = Just Exbi | |
| x < 2 ^ (80 :: Word) = Just Zebi | |
| otherwise = Just Yobi | |
formatS :: (Ord a, Num a, Show a, Integral a) => a -> ShowS | |
formatS x = maybe (shows x) pp (unit x) | |
where | |
pp u = shows (x `div` multiplier u) . showString (prefix u) |
This file contains hidden or 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
-- SI decimal prefixes of positive power. | |
-- | |
-- > http://www.bipm.org/en/si/prefixes.html | |
-- | |
{-# LANGUAGE Safe #-} | |
module Data.Unit.Dec | |
( Unit | |
, table, fromPrefix, prefix | |
, multiplier, unit, formatS | |
) | |
where | |
import Data.Maybe | |
import Data.Word | |
import Data.Tuple | |
data Unit | |
= Kilo -- ^ 10 ^ 3 | |
| Mega -- ^ 10 ^ 6 | |
| Giga -- ^ 10 ^ 9 | |
| Tera -- ^ 10 ^ 12 | |
| Peta -- ^ 10 ^ 15 | |
| Exa -- ^ 10 ^ 18 | |
| Zetta -- ^ 10 ^ 21 | |
| Yotta -- ^ 10 ^ 24 | |
deriving (Show, Read, Eq, Ord, Bounded, Enum) | |
table :: [(Unit, Char)] | |
table = map mk [minBound .. maxBound] | |
where | |
mk u = (u, head (show u)) | |
fromPrefix :: Char -> Maybe Unit | |
fromPrefix c = lookup c (map swap table) | |
-- | Uppercase. | |
prefix :: Unit -> Char | |
prefix u = fromJust (lookup u table) | |
multiplier :: Num a => Unit -> a | |
multiplier u = 10 ^ (3 * fromEnum u + 3) | |
unit :: (Ord a, Num a) => a -> Maybe Unit | |
unit x | x < 10 ^ (3 :: Word) = Nothing | |
| x < 10 ^ (6 :: Word) = Just Kilo | |
| x < 10 ^ (9 :: Word) = Just Mega | |
| x < 10 ^ (12 :: Word) = Just Giga | |
| x < 10 ^ (15 :: Word) = Just Tera | |
| x < 10 ^ (18 :: Word) = Just Peta | |
| x < 10 ^ (21 :: Word) = Just Exa | |
| x < 10 ^ (24 :: Word) = Just Zetta | |
| otherwise = Just Yotta | |
formatS :: (Ord a, Num a, Show a, Integral a) => a -> ShowS | |
formatS x = maybe (shows x) pp (unit x) | |
where | |
pp u = shows (x `div` multiplier u) . showChar (prefix u) |
This file contains hidden or 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
-- This module provides types which can be used for reading or | |
-- writing values of some specific quantity. | |
-- | |
-- For example this program: | |
-- | |
-- > main = do Size i <- read <$> System.IO.getLine | |
-- > print (Size i) | |
-- | |
-- will read /size/ of something in (not nessary pretty) format | |
-- and output the same value in pretty form: | |
-- | |
-- > "1B" -> "1B" | |
-- > "20000" -> "20KB" | |
-- > "10M" -> "10MB" | |
-- > "100gib" -> "107GiB" | |
-- | |
-- You could also use the /i/ as ordinary value of Word64. Parsing | |
-- is case insensitive. | |
-- | |
{-# LANGUAGE Trustworthy #-} | |
{-# LANGUAGE PatternGuards #-} | |
{-# LANGUAGE GeneralizedNewtypeDeriving #-} | |
module Data.Unit | |
( Count(Count, getCount) | |
, Size (Size, getSize) | |
) where | |
import Control.Applicative | |
import Data.Char | |
import Data.Unit.Bin as U2 | |
import Data.Unit.Dec as U10 | |
-- | Should be used for count of something. Suffixed with multiplier | |
-- without any unit. | |
-- | |
newtype Count a = Count { getCount :: a } | |
deriving (Eq, Ord, Bounded, Enum, Real, Num, Integral) | |
instance (Show a, Integral a) => Show (Count a) where | |
showsPrec _ = U10.formatS . getCount | |
instance (Read a, Num a) => Read (Count a) where | |
readsPrec p s = mk <$> readsPrec p s | |
where | |
mk (i, a : b : xs) | |
| Just u <- U2.fromPrefix [toUpper a, toLower b] | |
= (Count (i * (U2.multiplier u)), xs) | |
mk (i, x : xs) | Just u <- U10.fromPrefix (toUpper x) | |
= (Count (i * (U10.multiplier u)), xs) | |
mk (i, xs) = (Count i, xs) | |
-- | Should be used for size of data in bytes. Suffixed with unit 'B' | |
-- and multiplier by decimal power. | |
-- | |
-- Its guarantieed that @(read . show) :: Count -> Size@ will work for | |
-- any 'Count', but the opposite isn't true. | |
-- | |
newtype Size a = Size { getSize :: a } | |
deriving (Eq, Ord, Bounded, Enum, Real, Num, Integral) | |
instance (Show a, Integral a) => Show (Size a) where | |
showsPrec _ s = U10.formatS (getSize s) . showChar 'B' | |
instance (Read a, Num a) => Read (Size a) where | |
readsPrec p s = mk <$> readsPrec p s | |
where | |
mk (Count i, x : xs) | toUpper x == 'B' | |
= (Size i, xs) | |
mk (Count i, xs) = (Size i, xs) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment