{-# LANGUAGE LambdaCase, OverloadedStrings, InstanceSigs #-}
{-# LANGUAGE DerivingStrategies, GeneralizedNewtypeDeriving, DeriveGeneric, DeriveDataTypeable #-}
module Data.Digit where
import Prelude.Spiros
import GHC.Exts (IsString)
newtype Digit = Digit Int
deriving stock (Show,Read,Data)
deriving newtype (Eq,Ord,Num,Ix,NFData,Hashable)
instance Bounded Digit where
minBound = minimumDigit
maxBound = maximumDigit
instance Enum Digit where
toEnum :: Int -> Digit
toEnum = unsafeDigit :: Int -> Digit
fromEnum :: Digit -> Int
fromEnum = fromDigit
minimumDigit :: (Num a) => a
minimumDigit = 0
{-# SPECIALIZE minimumDigit :: Digit #-}
{-# SPECIALIZE minimumDigit :: Int #-}
maximumDigit :: (Num a) => a
maximumDigit = 9
{-# SPECIALIZE maximumDigit :: Digit #-}
{-# SPECIALIZE maximumDigit :: Int #-}
fromDigit :: Digit -> Int
fromDigit (Digit d) = d
toDigit :: (Integral a) => a -> Maybe Digit
toDigit i = if a <= i && i <= b
then Just $ Digit (fromIntegral i)
else Nothing
where
a = minimumDigit
b = maximumDigit
{-# SPECIALIZE toDigit :: Int -> Maybe Digit #-}
unsafeDigit :: (Integral a) => a -> Digit
unsafeDigit i = i & (toDigit >>> maybe (__ERROR__ e) id)
where
e = ("[spiros:Digit.unsafeDigit] a Digit must be a single-digit number")
{-# SPECIALIZE unsafeDigit :: Int -> Digit #-}
allDigits :: [Digit]
allDigits = [0..9]
parseDigit' :: Char -> Maybe Digit
parseDigit' = \case
'0' -> Just $ Digit 0
'1' -> Just $ Digit 1
'2' -> Just $ Digit 2
'3' -> Just $ Digit 3
'4' -> Just $ Digit 4
'5' -> Just $ Digit 5
'6' -> Just $ Digit 6
'7' -> Just $ Digit 7
'8' -> Just $ Digit 8
'9' -> Just $ Digit 9
_ -> Nothing
parseDigit :: (IsString s, Eq s) => s -> Maybe Digit
parseDigit = \case
"0" -> Just $ Digit 0
"1" -> Just $ Digit 1
"2" -> Just $ Digit 2
"3" -> Just $ Digit 3
"4" -> Just $ Digit 4
"5" -> Just $ Digit 5
"6" -> Just $ Digit 6
"7" -> Just $ Digit 7
"8" -> Just $ Digit 8
"9" -> Just $ Digit 9
_ -> Nothing