d10-1.0.1.0: src/D10/Num/Unsafe.hs
{-# language Unsafe, GeneralizedNewtypeDeriving #-}
module D10.Num.Unsafe (D10 (..)) where
import qualified D10.Predicate as Predicate
import Data.Char (chr, ord)
import Data.Hashable (Hashable)
import Data.Monoid (Endo (..))
---------------------------------------------------
-- | A value of some numeric type @a@ between
-- @'fromInteger' 0@ and @'fromInteger' 9@.
newtype D10 a =
D10_Unsafe a
-- ^ The constructor's name include the word "unsafe" as a reminder
-- that you should generally avoid using it directly, because it
-- allows constructing invalid 'D10' values.
deriving stock (Eq, Ord)
deriving newtype Hashable
---------------------------------------------------
instance Num a => Bounded (D10 a)
where
minBound = D10_Unsafe 0
maxBound = D10_Unsafe 9
---------------------------------------------------
instance Integral a => Enum (D10 a)
where
fromEnum :: D10 a -> Int
fromEnum (D10_Unsafe x) = fromIntegral x
toEnum :: Int -> D10 a
toEnum x | Predicate.isD10Int x = D10_Unsafe (fromIntegral x)
| otherwise = error "d10 must be between 0 and 9"
enumFrom :: D10 a -> [D10 a]
enumFrom x = enumFromTo x maxBound
enumFromThen :: D10 a -> D10 a -> [D10 a]
enumFromThen x y = enumFromThenTo x y bound
where
bound | fromEnum y >= fromEnum x = maxBound
| otherwise = minBound
succ (D10_Unsafe 9) = error "D10 overflow"
succ (D10_Unsafe x) = D10_Unsafe (succ x)
pred (D10_Unsafe 0) = error "D10 underflow"
pred (D10_Unsafe x) = D10_Unsafe (pred x)
---------------------------------------------------
instance Integral a => Show (D10 a) where
showsPrec _ x = showString "[d10|" . showsChar x . showString "|]"
showList xs = showString "[d10list|" . showsStr xs . showString "|]"
showsChar :: Integral a => D10 a -> ShowS
showsChar (D10_Unsafe x) = showChar $ chr (ord '0' + fromIntegral x)
showsStr :: Integral a => [D10 a] -> ShowS
showsStr = appEndo . foldMap (Endo . showsChar)