{-# LANGUAGE NoImplicitPrelude #-} module Data.Digit.Integral( -- * Binary integralBinaryNoZero , integralBinary , integralBinDigits , binDigitsIntegral -- * Octal , integralOctalNoZero , integralOctal , integralOctDigits , octDigitsIntegral -- * Decimal , integralDecimal , integralDecimalNoZero , integralDecDigits , decDigitsIntegral -- * Hexadecimal , integralHexadecimalNoZero , integralHexadecimal , integralHexDigits , hexDigitsIntegral -- * HEXADECIMAL , integralHEXADECIMALNoZero , integralHEXADECIMAL , integralHEXDigits , _HEXDigitsIntegral -- * HeXaDeCiMaL , integralHeXaDeCiMaLNoZero , integralHeXaDeCiMaL , _HeXDigitsIntegral ) where import Prelude (error) import Control.Lens.Extras(is) import Data.Digit.Binary import Data.Digit.Decimal import Data.Digit.Octal import Data.Digit.Hexadecimal import Data.Digit.HEXADECIMAL import Data.Digit.HeXaDeCiMaL import qualified Data.List.NonEmpty as NonEmpty import Papa -- $setup -- >>> import Data.Digit -- | -- -- >>> 1 ^? integralBinaryNoZero -- Just BinDigit1 -- -- >>> integralBinaryNoZero # BinDigit1 :: Integer -- 1 integralBinaryNoZero :: (Integral a, BinaryNoZero d) => Prism' a d integralBinaryNoZero = associatePrism (1, d1) [] -- | -- -- >>> 0 ^? integralBinary :: Maybe BinDigit -- Just BinDigit0 -- -- >>> integralBinary # BinDigit0 :: Integer -- 0 integralBinary :: (Integral a, Binary d) => Prism' a d integralBinary = associatePrism (0, d0) [(1, d1)] -- | -- >>> integralBinDigits (4 :: Int) -- Right (BinDigit1 :| [BinDigit0, BinDigit0]) -- -- >>> integralBinDigits (0 :: Int) -- Right (BinDigit0 :| []) -- -- >>> integralBinDigits (-1 :: Int) -- Left (BinDigit0 :| []) -- -- >>> integralBinDigits (-4 :: Int) -- Left (BinDigit1 :| [BinDigit1]) integralBinDigits :: Integral a => a -> Either (NonEmpty BinDigit) (NonEmpty BinDigit) integralBinDigits n = if n >= 0 then Right . NonEmpty.fromList $ go n [] else Left . NonEmpty.fromList $ go (-n - 1) [] where go k = let (q, r) = quotRem k 2 in (if q == 0 then id else go q) . ((r ^?! integralBinary) :) -- | -- >>> binDigitsIntegral (Right (BinDigit1 :| [BinDigit0, BinDigit0])) :: Int -- 4 -- -- >>> binDigitsIntegral (Right (BinDigit0 :| [])) :: Int -- 0 -- -- >>> binDigitsIntegral (Left (BinDigit0 :| [])) :: Int -- -1 -- -- >>> binDigitsIntegral (Left (BinDigit1 :| [BinDigit1])) :: Int -- -4 binDigitsIntegral :: Integral a => Either (NonEmpty BinDigit) (NonEmpty BinDigit) -> a binDigitsIntegral = either (\n -> -(go n) - 1) go where go = foldl' (\b a -> (integralBinary # a) + 2 * b) 0 -- | -- -- >>> 7 ^? integralOctalNoZero :: Maybe OctDigit -- Just OctDigit7 -- -- >>> integralOctalNoZero # OctDigit7 :: Integer -- 7 integralOctalNoZero :: (Integral a, OctalNoZero d) => Prism' a d integralOctalNoZero = associatePrism (1, d1) [(2, d2), (3, d3), (4, d4), (5, d5), (6, d6), (7, d7)] -- | -- -- >>> 7 ^? integralOctal :: Maybe OctDigit -- Just OctDigit7 -- -- >>> integralOctal # OctDigit7 :: Integer -- 7 integralOctal :: (Integral a, Octal d) => Prism' a d integralOctal = associatePrism (0, d0) [(1, d1), (2, d2), (3, d3), (4, d4), (5, d5), (6, d6), (7, d7)] -- | -- >>> integralOctDigits (64 :: Int) -- Right (OctDigit1 :| [OctDigit0, OctDigit0]) -- -- >>> integralOctDigits (0 :: Int) -- Right (OctDigit0 :| []) -- -- >>> integralOctDigits (-1 :: Int) -- Left (OctDigit0 :| []) -- -- >>> integralOctDigits (-64 :: Int) -- Left (OctDigit7 :| [OctDigit7]) integralOctDigits :: Integral a => a -> Either (NonEmpty OctDigit) (NonEmpty OctDigit) integralOctDigits n = if n >= 0 then Right . NonEmpty.fromList $ go n [] else Left . NonEmpty.fromList $ go (-n - 1) [] where go k = let (q, r) = quotRem k 8 in (if q == 0 then id else go q) . ((r ^?! integralOctal) :) -- | -- >>> octDigitsIntegral (Right (OctDigit1 :| [OctDigit0, OctDigit0])) :: Int -- 64 -- -- >>> octDigitsIntegral (Right (OctDigit0 :| [])) :: Int -- 0 -- -- >>> octDigitsIntegral (Left (OctDigit0 :| [])) :: Int -- -1 -- -- >>> octDigitsIntegral (Left (OctDigit7 :| [OctDigit7])) :: Int -- -64 octDigitsIntegral :: Integral a => Either (NonEmpty OctDigit) (NonEmpty OctDigit) -> a octDigitsIntegral = either (\n -> -(go n) - 1) go where go = foldl' (\b a -> (integralOctal # a) + 8 * b) 0 -- | -- >>> 9 ^? integralDecimalNoZero :: Maybe DecDigit -- Just DecDigit9 -- -- >>> integralDecimalNoZero # DecDigit9 :: Integer -- 9 integralDecimalNoZero :: (Integral a, DecimalNoZero d) => Prism' a d integralDecimalNoZero = associatePrism (1, d1) [(2, d2), (3, d3), (4, d4), (5, d5), (6, d6), (7, d7), (8, d8), (9, d9)] -- | -- >>> 9 ^? integralDecimal :: Maybe DecDigit -- Just DecDigit9 -- -- >>> integralDecimal # DecDigit9 :: Integer -- 9 integralDecimal :: (Integral a, Decimal d) => Prism' a d integralDecimal = associatePrism (0, d0) [(1, d1), (2, d2), (3, d3), (4, d4), (5, d5), (6, d6), (7, d7), (8, d8), (9, d9)] -- | -- >>> integralDecDigits (100 :: Int) -- Right (DecDigit1 :| [DecDigit0, DecDigit0]) -- -- >>> integralDecDigits (0 :: Int) -- Right (DecDigit0 :| []) -- -- >>> integralDecDigits (-1 :: Int) -- Left (DecDigit0 :| []) -- -- >>> integralDecDigits (-100 :: Int) -- Left (DecDigit9 :| [DecDigit9]) integralDecDigits :: Integral a => a -> Either (NonEmpty DecDigit) (NonEmpty DecDigit) integralDecDigits n = if n >= 0 then Right . NonEmpty.fromList $ go n [] else Left . NonEmpty.fromList $ go (-n - 1) [] where go k = let (q, r) = quotRem k 10 in (if q == 0 then id else go q) . ((r ^?! integralDecimal) :) -- | -- >>> decDigitsIntegral (Right (DecDigit1 :| [DecDigit0, DecDigit0])) :: Int -- 100 -- -- >>> decDigitsIntegral (Right (DecDigit0 :| [])) :: Int -- 0 -- -- >>> decDigitsIntegral (Left (DecDigit0 :| [])) :: Int -- -1 -- -- >>> decDigitsIntegral (Left (DecDigit9 :| [DecDigit9])) :: Int -- -100 decDigitsIntegral :: Integral a => Either (NonEmpty DecDigit) (NonEmpty DecDigit) -> a decDigitsIntegral = either (\n -> -(go n) - 1) go where go = foldl' (\b a -> (integralDecimal # a) + 10 * b) 0 -- | -- -- >>> 15 ^? integralHexadecimalNoZero :: Maybe HexDigit -- Just HexDigitf -- -- >>> integralHexadecimalNoZero # HexDigitf :: Integer -- 15 integralHexadecimalNoZero :: (Integral a, HexadecimalNoZero d) => Prism' a d integralHexadecimalNoZero = associatePrism (1, d1) [(2, d2), (3, d3), (4, d4), (5, d5), (6, d6), (7, d7), (8, d8), (9, d9), (10, da), (11, db), (12, dc), (13, dd), (14, de), (15, df)] -- | -- -- >>> 15 ^? integralHexadecimal :: Maybe HexDigit -- Just HexDigitf -- -- >>> integralHexadecimal # HexDigitf :: Integer -- 15 integralHexadecimal :: (Integral a, Hexadecimal d) => Prism' a d integralHexadecimal = associatePrism (0, d0) [(1, d1), (2, d2), (3, d3), (4, d4), (5, d5), (6, d6), (7, d7), (8, d8), (9, d9), (10, da), (11, db), (12, dc), (13, dd), (14, de), (15, df)] -- | -- >>> integralHexDigits (256 :: Int) -- Right (HexDigit1 :| [HexDigit0, HexDigit0]) -- -- >>> integralHexDigits (0 :: Int) -- Right (HexDigit0 :| []) -- -- >>> integralHexDigits (-1 :: Int) -- Left (HexDigit0 :| []) -- -- >>> integralHexDigits (-256 :: Int) -- Left (HexDigitf :| [HexDigitf]) integralHexDigits :: Integral a => a -> Either (NonEmpty HexDigit) (NonEmpty HexDigit) integralHexDigits n = if n >= 0 then Right . NonEmpty.fromList $ go n [] else Left . NonEmpty.fromList $ go (-n - 1) [] where go k = let (q, r) = quotRem k 16 in (if q == 0 then id else go q) . ((r ^?! integralHexadecimal) :) -- | -- >>> hexDigitsIntegral (Right (HexDigit1 :| [HexDigit0, HexDigit0])) :: Int -- 256 -- -- >>> hexDigitsIntegral (Right (HexDigit0 :| [])) :: Int -- 0 -- -- >>> hexDigitsIntegral (Left (HexDigit0 :| [])) :: Int -- -1 -- -- >>> hexDigitsIntegral (Left (HexDigitf :| [HexDigitf])) :: Int -- -256 hexDigitsIntegral :: Integral a => Either (NonEmpty HexDigit) (NonEmpty HexDigit) -> a hexDigitsIntegral = either (\n -> -(go n) - 1) go where go = foldl' (\b a -> (integralHexadecimal # a) + 16 * b) 0 -- | -- -- >>> 15 ^? integralHEXADECIMALNoZero :: Maybe HEXDigit -- Just HEXDigitF -- -- >>> integralHEXADECIMALNoZero # HEXDigitF :: Integer -- 15 integralHEXADECIMALNoZero :: (Integral a, HEXADECIMALNoZero d) => Prism' a d integralHEXADECIMALNoZero = associatePrism (1, d1) [(2, d2), (3, d3), (4, d4), (5, d5), (6, d6), (7, d7), (8, d8), (9, d9), (10, dA), (11, dB), (12, dC), (13, dD), (14, dE), (15, dF)] -- | -- -- >>> 15 ^? integralHEXADECIMAL :: Maybe HEXDigit -- Just HEXDigitF -- -- >>> integralHEXADECIMAL # HEXDigitF :: Integer -- 15 integralHEXADECIMAL :: (Integral a, HEXADECIMAL d) => Prism' a d integralHEXADECIMAL = associatePrism (0, d0) [(1, d1), (2, d2), (3, d3), (4, d4), (5, d5), (6, d6), (7, d7), (8, d8), (9, d9), (10, dA), (11, dB), (12, dC), (13, dD), (14, dE), (15, dF)] -- | -- >>> integralHEXDigits (256 :: Int) -- Right (HEXDigit1 :| [HEXDigit0, HEXDigit0]) -- -- >>> integralHEXDigits (0 :: Int) -- Right (HEXDigit0 :| []) -- -- >>> integralHEXDigits (-1 :: Int) -- Left (HEXDigit0 :| []) -- -- >>> integralHEXDigits (-256 :: Int) -- Left (HEXDigitF :| [HEXDigitF]) integralHEXDigits :: Integral a => a -> Either (NonEmpty HEXDigit) (NonEmpty HEXDigit) integralHEXDigits n = if n >= 0 then Right . NonEmpty.fromList $ go n [] else Left . NonEmpty.fromList $ go (-n - 1) [] where go k = let (q, r) = quotRem k 16 in (if q == 0 then id else go q) . ((r ^?! integralHEXADECIMAL) :) -- | -- >>> HEXDigitsIntegral (Right (HEXDigit1 :| [HEXDigit0, HEXDigit0])) :: Int -- 256 -- -- >>> HEXDigitsIntegral (Right (HEXDigit0 :| [])) :: Int -- 0 -- -- >>> HEXDigitsIntegral (Left (HEXDigit0 :| [])) :: Int -- -1 -- -- >>> HEXDigitsIntegral (Left (HEXDigitF :| [HEXDigitF])) :: Int -- -256 _HEXDigitsIntegral :: Integral a => Either (NonEmpty HEXDigit) (NonEmpty HEXDigit) -> a _HEXDigitsIntegral = either (\n -> -(go n) - 1) go where go = foldl' (\b a -> (integralHEXADECIMAL # a) + 16 * b) 0 -- | -- -- >>> 15 ^? integralHeXaDeCiMaLNoZero :: Maybe HeXDigit -- Just HeXDigitF -- -- >>> integralHeXaDeCiMaLNoZero # HeXDigitF :: Integer -- 15 integralHeXaDeCiMaLNoZero :: (Integral a, HeXaDeCiMaLNoZero d) => Review a d integralHeXaDeCiMaLNoZero = unto (outside d1 .~ (\_ -> 1) $ outside d2 .~ (\_ -> 2) $ outside d3 .~ (\_ -> 3) $ outside d4 .~ (\_ -> 4) $ outside d5 .~ (\_ -> 5) $ outside d6 .~ (\_ -> 6) $ outside d7 .~ (\_ -> 7) $ outside d8 .~ (\_ -> 8) $ outside d9 .~ (\_ -> 9) $ outside da .~ (\_ -> 10) $ outside dA .~ (\_ -> 10) $ outside db .~ (\_ -> 11) $ outside dB .~ (\_ -> 11) $ outside dc .~ (\_ -> 12) $ outside dC .~ (\_ -> 12) $ outside dd .~ (\_ -> 13) $ outside dD .~ (\_ -> 13) $ outside de .~ (\_ -> 14) $ outside dE .~ (\_ -> 14) $ outside df .~ (\_ -> 15) $ outside dF .~ (\_ -> 15) $ error "incomplete pattern") -- | -- -- >>> 15 ^? integralHeXaDeCiMaL :: Maybe HeXDigit -- Just HeXDigitF -- -- >>> integralHeXaDeCiMaL # HeXDigitF :: Integer -- 15 integralHeXaDeCiMaL :: (Integral a, HeXaDeCiMaL d) => Review a d integralHeXaDeCiMaL = unto (outside d0 .~ (\_ -> 0) $ outside d1 .~ (\_ -> 1) $ outside d2 .~ (\_ -> 2) $ outside d3 .~ (\_ -> 3) $ outside d4 .~ (\_ -> 4) $ outside d5 .~ (\_ -> 5) $ outside d6 .~ (\_ -> 6) $ outside d7 .~ (\_ -> 7) $ outside d8 .~ (\_ -> 8) $ outside d9 .~ (\_ -> 9) $ outside da .~ (\_ -> 10) $ outside dA .~ (\_ -> 10) $ outside db .~ (\_ -> 11) $ outside dB .~ (\_ -> 11) $ outside dc .~ (\_ -> 12) $ outside dC .~ (\_ -> 12) $ outside dd .~ (\_ -> 13) $ outside dD .~ (\_ -> 13) $ outside de .~ (\_ -> 14) $ outside dE .~ (\_ -> 14) $ outside df .~ (\_ -> 15) $ outside dF .~ (\_ -> 15) $ error "incomplete pattern") -- | -- >>> HeXDigitsIntegral (Right (HeXDigit1 :| [HeXDigit0, HeXDigit0])) :: Int -- 256 -- -- >>> HeXDigitsIntegral (Right (HeXDigit0 :| [])) :: Int -- 0 -- -- >>> HeXDigitsIntegral (Left (HeXDigit0 :| [])) :: Int -- -1 -- -- >>> HeXDigitsIntegral (Left (HeXDigitF :| [HeXDigitF])) :: Int -- -256 _HeXDigitsIntegral :: Integral a => Either (NonEmpty HeXDigit) (NonEmpty HeXDigit) -> a _HeXDigitsIntegral = either (\n -> -(go n) - 1) go where go = foldl' (\b a -> (integralHeXaDeCiMaL # a) + 16 * b) 0 ---- not exported associatePrism :: (Eq b, Choice p, Applicative f) => (b, APrism a a () ()) -> [(b, APrism a a () ())] -> p a (f a) -> p b (f b) associatePrism def z = prism' (\d -> fst (fromMaybe def (find (\(_, w) -> is w d) z))) (\i -> (\p -> clonePrism p # ()) <$> lookup i (def:z))