{-# LANGUAGE NoImplicitPrelude #-}
module Data.Digit.Integral(
integralBinaryNoZero
, integralBinary
, integralBinDigits
, binDigitsIntegral
, integralOctalNoZero
, integralOctal
, integralOctDigits
, octDigitsIntegral
, integralDecimal
, integralDecimalNoZero
, integralDecDigits
, decDigitsIntegral
, integralHexadecimalNoZero
, integralHexadecimal
, integralHexDigits
, hexDigitsIntegral
, integralHEXADECIMALNoZero
, integralHEXADECIMAL
, integralHEXDigits
, _HEXDigitsIntegral
, integralHeXaDeCiMaLNoZero
, integralHeXaDeCiMaL
, _HeXDigitsIntegral
, mod10
, addDecDigit
, addDecDigit'
) where
import Prelude (Eq, Integral, error, fst, lookup,
quotRem, (*), (+), (-), (==), (>=), mod, divMod)
import Control.Applicative (Applicative)
import Control.Category (id, (.))
import Control.Lens (APrism, Choice, Prism', Review,
clonePrism, outside, prism', unto, over, _1,
( # ), (.~), (^?!), (^?))
import Control.Lens.Extras (is)
import Data.Bool (Bool, bool)
import Data.Either (Either (..), either)
import Data.Foldable (find, foldl')
import Data.Function (($),const)
import Data.Functor ((<$>))
import Data.Int (Int)
import Data.List.NonEmpty (NonEmpty)
import Data.Maybe (fromMaybe)
import Data.Ord ((>))
import Data.Digit.Binary
import Data.Digit.Decimal
import Data.Digit.Hexadecimal.LowerCase
import Data.Digit.Hexadecimal.UpperCase
import Data.Digit.Hexadecimal.MixedCase
import Data.Digit.Octal
import qualified Data.List.NonEmpty as NonEmpty
integralBinaryNoZero ::
(Integral a, BinaryNoZero d) =>
Prism'
a
d
integralBinaryNoZero =
associatePrism (1, d1) []
integralBinary ::
(Integral a, Binary d) =>
Prism'
a
d
integralBinary =
associatePrism (0, d0) [(1, d1)]
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 :: 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
integralOctalNoZero ::
(Integral a, OctalNoZero d) =>
Prism'
a
d
integralOctalNoZero =
associatePrism (1, d1) [(2, d2), (3, d3), (4, d4), (5, d5), (6, d6), (7, d7)]
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 :: 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 :: 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
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)]
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 :: 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 :: 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
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)]
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 :: 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 :: 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
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)]
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 :: 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 :: 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
integralHeXaDeCiMaLNoZero ::
(Integral a, HeXaDeCiMaLNoZero d) =>
Review
a
d
integralHeXaDeCiMaLNoZero =
unto
(outside d1 .~ const 1 $
outside d2 .~ const 2 $
outside d3 .~ const 3 $
outside d4 .~ const 4 $
outside d5 .~ const 5 $
outside d6 .~ const 6 $
outside d7 .~ const 7 $
outside d8 .~ const 8 $
outside d9 .~ const 9 $
outside da .~ const 10 $
outside dA .~ const 10 $
outside db .~ const 11 $
outside dB .~ const 11 $
outside dc .~ const 12 $
outside dC .~ const 12 $
outside dd .~ const 13 $
outside dD .~ const 13 $
outside de .~ const 14 $
outside dE .~ const 14 $
outside df .~ const 15 $
outside dF .~ const 15 $
error "incomplete pattern")
integralHeXaDeCiMaL ::
(Integral a, HeXaDeCiMaL d) =>
Review
a
d
integralHeXaDeCiMaL =
unto
(outside d0 .~ const 0 $
outside d1 .~ const 1 $
outside d2 .~ const 2 $
outside d3 .~ const 3 $
outside d4 .~ const 4 $
outside d5 .~ const 5 $
outside d6 .~ const 6 $
outside d7 .~ const 7 $
outside d8 .~ const 8 $
outside d9 .~ const 9 $
outside da .~ const 10 $
outside dA .~ const 10 $
outside db .~ const 11 $
outside dB .~ const 11 $
outside dc .~ const 12 $
outside dC .~ const 12 $
outside dd .~ const 13 $
outside dD .~ const 13 $
outside de .~ const 14 $
outside dE .~ const 14 $
outside df .~ const 15 $
outside dF .~ const 15 $
error "incomplete pattern")
_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
mod10 ::
Integral a =>
a
-> DecDigit
mod10 n =
let r = n `mod` 10
in fromMaybe (mod10 r) (r ^? integralDecimal)
addDecDigit ::
DecDigit
-> DecDigit
-> (Bool, DecDigit)
addDecDigit a b =
let (x, r) =
(integralDecimal # a + integralDecimal # b) `divMod` 10
in (x > 0, mod10 (r :: Int))
addDecDigit' ::
DecDigit
-> DecDigit
-> (DecDigit, DecDigit)
addDecDigit' a b =
over _1 (bool x0 x1) (addDecDigit a b)
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))