packages feed

d10 0.3.0.1 → 1

raw patch · 31 files changed

+3108/−2948 lines, 31 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Data.D10.Char: (*) :: D10 -> D10 -> D10
- Data.D10.Char: (+) :: D10 -> D10 -> D10
- Data.D10.Char: (-) :: D10 -> D10 -> D10
- Data.D10.Char: D10_Unsafe :: Char -> D10
- Data.D10.Char: charD10Either :: Char -> Either String D10
- Data.D10.Char: charD10Fail :: MonadFail m => Char -> m D10
- Data.D10.Char: charD10Maybe :: Char -> Maybe D10
- Data.D10.Char: d10 :: QuasiQuoter
- Data.D10.Char: d10Char :: D10 -> Char
- Data.D10.Char: d10Exp :: Integer -> Q Exp
- Data.D10.Char: d10Int :: D10 -> Int
- Data.D10.Char: d10Integer :: D10 -> Integer
- Data.D10.Char: d10ListExp :: String -> Q Exp
- Data.D10.Char: d10ListPat :: String -> Q Pat
- Data.D10.Char: d10Nat :: D10 -> Natural
- Data.D10.Char: d10Num :: Num a => D10 -> a
- Data.D10.Char: d10Pat :: Integer -> Q Pat
- Data.D10.Char: d10Str :: D10 -> String
- Data.D10.Char: d10list :: QuasiQuoter
- Data.D10.Char: instance GHC.Classes.Eq Data.D10.Char.D10
- Data.D10.Char: instance GHC.Classes.Ord Data.D10.Char.D10
- Data.D10.Char: instance GHC.Enum.Bounded Data.D10.Char.D10
- Data.D10.Char: instance GHC.Enum.Enum Data.D10.Char.D10
- Data.D10.Char: instance GHC.Show.Show Data.D10.Char.D10
- Data.D10.Char: instance Language.Haskell.TH.Syntax.Lift Data.D10.Char.D10
- Data.D10.Char: intD10Either :: Int -> Either String D10
- Data.D10.Char: intD10Fail :: MonadFail m => Int -> m D10
- Data.D10.Char: intD10Maybe :: Int -> Maybe D10
- Data.D10.Char: intMod10 :: Int -> D10
- Data.D10.Char: integerD10Either :: Integer -> Either String D10
- Data.D10.Char: integerD10Fail :: MonadFail m => Integer -> m D10
- Data.D10.Char: integerD10Maybe :: Integer -> Maybe D10
- Data.D10.Char: integerMod10 :: Integer -> D10
- Data.D10.Char: integralD10Either :: Integral a => a -> Either String D10
- Data.D10.Char: integralD10Fail :: (Integral a, MonadFail m) => a -> m D10
- Data.D10.Char: integralD10Maybe :: Integral a => a -> Maybe D10
- Data.D10.Char: integralMod10 :: Integral a => a -> D10
- Data.D10.Char: natD10Either :: Natural -> Either String D10
- Data.D10.Char: natD10Fail :: MonadFail m => Natural -> m D10
- Data.D10.Char: natD10Maybe :: Natural -> Maybe D10
- Data.D10.Char: natMod10 :: Natural -> D10
- Data.D10.Char: newtype D10
- Data.D10.Char: strD10Either :: String -> Either String D10
- Data.D10.Char: strD10Fail :: MonadFail m => String -> m D10
- Data.D10.Char: strD10ListEither :: String -> Either String [D10]
- Data.D10.Char: strD10ListFail :: MonadFail m => String -> m [D10]
- Data.D10.Char: strD10ListMaybe :: String -> Maybe [D10]
- Data.D10.Char: strD10Maybe :: String -> Maybe D10
- Data.D10.Num: (*) :: Integral a => D10 a -> D10 a -> D10 a
- Data.D10.Num: (+) :: Integral a => D10 a -> D10 a -> D10 a
- Data.D10.Num: (-) :: Integral a => D10 a -> D10 a -> D10 a
- Data.D10.Num: D10_Unsafe :: a -> D10 a
- Data.D10.Num: charD10Either :: Num a => Char -> Either String (D10 a)
- Data.D10.Num: charD10Fail :: (Num a, MonadFail m) => Char -> m (D10 a)
- Data.D10.Num: charD10Maybe :: Num a => Char -> Maybe (D10 a)
- Data.D10.Num: d10 :: QuasiQuoter
- Data.D10.Num: d10Char :: Integral a => D10 a -> Char
- Data.D10.Num: d10Exp :: Integer -> Q Exp
- Data.D10.Num: d10Int :: Integral a => D10 a -> Int
- Data.D10.Num: d10Integer :: Integral a => D10 a -> Integer
- Data.D10.Num: d10ListExp :: String -> Q Exp
- Data.D10.Num: d10ListPat :: String -> Q Pat
- Data.D10.Num: d10Nat :: Integral a => D10 a -> Natural
- Data.D10.Num: d10Num :: (Integral b, Num a) => D10 b -> a
- Data.D10.Num: d10Pat :: Integer -> Q Pat
- Data.D10.Num: d10Str :: Integral a => D10 a -> String
- Data.D10.Num: d10list :: QuasiQuoter
- Data.D10.Num: instance GHC.Classes.Eq a => GHC.Classes.Eq (Data.D10.Num.D10 a)
- Data.D10.Num: instance GHC.Classes.Ord a => GHC.Classes.Ord (Data.D10.Num.D10 a)
- Data.D10.Num: instance GHC.Num.Num a => GHC.Enum.Bounded (Data.D10.Num.D10 a)
- Data.D10.Num: instance GHC.Real.Integral a => GHC.Enum.Enum (Data.D10.Num.D10 a)
- Data.D10.Num: instance GHC.Real.Integral a => GHC.Show.Show (Data.D10.Num.D10 a)
- Data.D10.Num: instance Language.Haskell.TH.Syntax.Lift a => Language.Haskell.TH.Syntax.Lift (Data.D10.Num.D10 a)
- Data.D10.Num: intD10Either :: Num a => Int -> Either String (D10 a)
- Data.D10.Num: intD10Fail :: (Num a, MonadFail m) => Int -> m (D10 a)
- Data.D10.Num: intD10Maybe :: Num a => Int -> Maybe (D10 a)
- Data.D10.Num: intMod10 :: Num a => Int -> D10 a
- Data.D10.Num: integerD10Either :: Num a => Integer -> Either String (D10 a)
- Data.D10.Num: integerD10Fail :: (Num a, MonadFail m) => Integer -> m (D10 a)
- Data.D10.Num: integerD10Maybe :: Num a => Integer -> Maybe (D10 a)
- Data.D10.Num: integerMod10 :: Num a => Integer -> D10 a
- Data.D10.Num: integralD10Either :: (Num b, Integral a) => a -> Either String (D10 b)
- Data.D10.Num: integralD10Fail :: (Num b, Integral a, MonadFail m) => a -> m (D10 b)
- Data.D10.Num: integralD10Maybe :: (Num b, Integral a) => a -> Maybe (D10 b)
- Data.D10.Num: integralMod10 :: (Num b, Integral a) => a -> D10 b
- Data.D10.Num: natD10Either :: Num a => Natural -> Either String (D10 a)
- Data.D10.Num: natD10Fail :: (Num a, MonadFail m) => Natural -> m (D10 a)
- Data.D10.Num: natD10Maybe :: Num a => Natural -> Maybe (D10 a)
- Data.D10.Num: natMod10 :: Num a => Natural -> D10 a
- Data.D10.Num: newtype D10 a
- Data.D10.Num: strD10Either :: Num a => String -> Either String (D10 a)
- Data.D10.Num: strD10Fail :: (Num a, MonadFail m) => String -> m (D10 a)
- Data.D10.Num: strD10ListEither :: Num a => String -> Either String [D10 a]
- Data.D10.Num: strD10ListFail :: (Num a, MonadFail m) => String -> m [D10 a]
- Data.D10.Num: strD10ListMaybe :: Num a => String -> Maybe [D10 a]
- Data.D10.Num: strD10Maybe :: Num a => String -> Maybe (D10 a)
- Data.D10.Predicate: isD10Char :: Char -> Bool
- Data.D10.Predicate: isD10Int :: Int -> Bool
- Data.D10.Predicate: isD10Integer :: Integer -> Bool
- Data.D10.Predicate: isD10Integral :: Integral a => a -> Bool
- Data.D10.Predicate: isD10ListStr :: String -> Bool
- Data.D10.Predicate: isD10Nat :: Natural -> Bool
- Data.D10.Predicate: isD10Str :: String -> Bool
- Data.D10.Safe: (*) :: D10 -> D10 -> D10
- Data.D10.Safe: (+) :: D10 -> D10 -> D10
- Data.D10.Safe: (-) :: D10 -> D10 -> D10
- Data.D10.Safe: D0 :: D10
- Data.D10.Safe: D1 :: D10
- Data.D10.Safe: D2 :: D10
- Data.D10.Safe: D3 :: D10
- Data.D10.Safe: D4 :: D10
- Data.D10.Safe: D5 :: D10
- Data.D10.Safe: D6 :: D10
- Data.D10.Safe: D7 :: D10
- Data.D10.Safe: D8 :: D10
- Data.D10.Safe: D9 :: D10
- Data.D10.Safe: charD10Either :: Char -> Either String D10
- Data.D10.Safe: charD10Fail :: MonadFail m => Char -> m D10
- Data.D10.Safe: charD10Maybe :: Char -> Maybe D10
- Data.D10.Safe: d10Char :: D10 -> Char
- Data.D10.Safe: d10Int :: D10 -> Int
- Data.D10.Safe: d10Integer :: D10 -> Integer
- Data.D10.Safe: d10ListExp :: String -> Q Exp
- Data.D10.Safe: d10ListPat :: String -> Q Pat
- Data.D10.Safe: d10Nat :: D10 -> Natural
- Data.D10.Safe: d10Num :: Num a => D10 -> a
- Data.D10.Safe: d10Str :: D10 -> String
- Data.D10.Safe: d10list :: QuasiQuoter
- Data.D10.Safe: data D10
- Data.D10.Safe: instance Data.Data.Data Data.D10.Safe.D10
- Data.D10.Safe: instance GHC.Classes.Eq Data.D10.Safe.D10
- Data.D10.Safe: instance GHC.Classes.Ord Data.D10.Safe.D10
- Data.D10.Safe: instance GHC.Enum.Bounded Data.D10.Safe.D10
- Data.D10.Safe: instance GHC.Enum.Enum Data.D10.Safe.D10
- Data.D10.Safe: instance GHC.Generics.Generic Data.D10.Safe.D10
- Data.D10.Safe: instance GHC.Show.Show Data.D10.Safe.D10
- Data.D10.Safe: instance Language.Haskell.TH.Syntax.Lift Data.D10.Safe.D10
- Data.D10.Safe: intD10Either :: Int -> Either String D10
- Data.D10.Safe: intD10Fail :: MonadFail m => Int -> m D10
- Data.D10.Safe: intD10Maybe :: Int -> Maybe D10
- Data.D10.Safe: intMod10 :: Int -> D10
- Data.D10.Safe: integerD10Either :: Integer -> Either String D10
- Data.D10.Safe: integerD10Fail :: MonadFail m => Integer -> m D10
- Data.D10.Safe: integerD10Maybe :: Integer -> Maybe D10
- Data.D10.Safe: integerMod10 :: Integer -> D10
- Data.D10.Safe: integralD10Either :: Integral a => a -> Either String D10
- Data.D10.Safe: integralD10Fail :: (Integral a, MonadFail m) => a -> m D10
- Data.D10.Safe: integralD10Maybe :: Integral a => a -> Maybe D10
- Data.D10.Safe: integralMod10 :: Integral a => a -> D10
- Data.D10.Safe: natD10Either :: Natural -> Either String D10
- Data.D10.Safe: natD10Fail :: MonadFail m => Natural -> m D10
- Data.D10.Safe: natD10Maybe :: Natural -> Maybe D10
- Data.D10.Safe: natMod10 :: Natural -> D10
- Data.D10.Safe: strD10Either :: String -> Either String D10
- Data.D10.Safe: strD10Fail :: MonadFail m => String -> m D10
- Data.D10.Safe: strD10ListEither :: String -> Either String [D10]
- Data.D10.Safe: strD10ListFail :: MonadFail m => String -> m [D10]
- Data.D10.Safe: strD10ListMaybe :: String -> Maybe [D10]
- Data.D10.Safe: strD10Maybe :: String -> Maybe D10
+ D10.Char: charD10Either :: Char -> Either String D10
+ D10.Char: charD10Fail :: MonadFail m => Char -> m D10
+ D10.Char: charD10Maybe :: Char -> Maybe D10
+ D10.Char: d10 :: QuasiQuoter
+ D10.Char: d10Char :: D10 -> Char
+ D10.Char: d10Exp :: Integer -> Q Exp
+ D10.Char: d10Int :: D10 -> Int
+ D10.Char: d10Integer :: D10 -> Integer
+ D10.Char: d10ListExp :: String -> Q Exp
+ D10.Char: d10ListPat :: String -> Q Pat
+ D10.Char: d10Nat :: D10 -> Natural
+ D10.Char: d10Num :: Num a => D10 -> a
+ D10.Char: d10Pat :: Integer -> Q Pat
+ D10.Char: d10Str :: D10 -> String
+ D10.Char: d10list :: QuasiQuoter
+ D10.Char: data D10
+ D10.Char: intD10Either :: Int -> Either String D10
+ D10.Char: intD10Fail :: MonadFail m => Int -> m D10
+ D10.Char: intD10Maybe :: Int -> Maybe D10
+ D10.Char: intMod10 :: Int -> D10
+ D10.Char: integerD10Either :: Integer -> Either String D10
+ D10.Char: integerD10Fail :: MonadFail m => Integer -> m D10
+ D10.Char: integerD10Maybe :: Integer -> Maybe D10
+ D10.Char: integerMod10 :: Integer -> D10
+ D10.Char: integralD10Either :: Integral a => a -> Either String D10
+ D10.Char: integralD10Fail :: (Integral a, MonadFail m) => a -> m D10
+ D10.Char: integralD10Maybe :: Integral a => a -> Maybe D10
+ D10.Char: integralMod10 :: Integral a => a -> D10
+ D10.Char: natD10Either :: Natural -> Either String D10
+ D10.Char: natD10Fail :: MonadFail m => Natural -> m D10
+ D10.Char: natD10Maybe :: Natural -> Maybe D10
+ D10.Char: natMod10 :: Natural -> D10
+ D10.Char: strD10Either :: String -> Either String D10
+ D10.Char: strD10Fail :: MonadFail m => String -> m D10
+ D10.Char: strD10ListEither :: String -> Either String [D10]
+ D10.Char: strD10ListFail :: MonadFail m => String -> m [D10]
+ D10.Char: strD10ListMaybe :: String -> Maybe [D10]
+ D10.Char: strD10Maybe :: String -> Maybe D10
+ D10.Char.Arithmetic: (*) :: D10 -> D10 -> D10
+ D10.Char.Arithmetic: (+) :: D10 -> D10 -> D10
+ D10.Char.Arithmetic: (-) :: D10 -> D10 -> D10
+ D10.Char.Conversions: charD10Either :: Char -> Either String D10
+ D10.Char.Conversions: charD10Fail :: MonadFail m => Char -> m D10
+ D10.Char.Conversions: charD10Maybe :: Char -> Maybe D10
+ D10.Char.Conversions: d10Char :: D10 -> Char
+ D10.Char.Conversions: d10Int :: D10 -> Int
+ D10.Char.Conversions: d10Integer :: D10 -> Integer
+ D10.Char.Conversions: d10Nat :: D10 -> Natural
+ D10.Char.Conversions: d10Num :: Num a => D10 -> a
+ D10.Char.Conversions: d10Str :: D10 -> String
+ D10.Char.Conversions: intD10Either :: Int -> Either String D10
+ D10.Char.Conversions: intD10Fail :: MonadFail m => Int -> m D10
+ D10.Char.Conversions: intD10Maybe :: Int -> Maybe D10
+ D10.Char.Conversions: intMod10 :: Int -> D10
+ D10.Char.Conversions: integerD10Either :: Integer -> Either String D10
+ D10.Char.Conversions: integerD10Fail :: MonadFail m => Integer -> m D10
+ D10.Char.Conversions: integerD10Maybe :: Integer -> Maybe D10
+ D10.Char.Conversions: integerMod10 :: Integer -> D10
+ D10.Char.Conversions: integralD10Either :: Integral a => a -> Either String D10
+ D10.Char.Conversions: integralD10Fail :: (Integral a, MonadFail m) => a -> m D10
+ D10.Char.Conversions: integralD10Maybe :: Integral a => a -> Maybe D10
+ D10.Char.Conversions: integralMod10 :: Integral a => a -> D10
+ D10.Char.Conversions: natD10Either :: Natural -> Either String D10
+ D10.Char.Conversions: natD10Fail :: MonadFail m => Natural -> m D10
+ D10.Char.Conversions: natD10Maybe :: Natural -> Maybe D10
+ D10.Char.Conversions: natMod10 :: Natural -> D10
+ D10.Char.Conversions: strD10Either :: String -> Either String D10
+ D10.Char.Conversions: strD10Fail :: MonadFail m => String -> m D10
+ D10.Char.Conversions: strD10ListEither :: String -> Either String [D10]
+ D10.Char.Conversions: strD10ListFail :: MonadFail m => String -> m [D10]
+ D10.Char.Conversions: strD10ListMaybe :: String -> Maybe [D10]
+ D10.Char.Conversions: strD10Maybe :: String -> Maybe D10
+ D10.Char.Quotes: d10 :: QuasiQuoter
+ D10.Char.Quotes: d10list :: QuasiQuoter
+ D10.Char.Splices: d10Exp :: Integer -> Q Exp
+ D10.Char.Splices: d10ListExp :: String -> Q Exp
+ D10.Char.Splices: d10ListPat :: String -> Q Pat
+ D10.Char.Splices: d10Pat :: Integer -> Q Pat
+ D10.Char.Type: data D10
+ D10.Char.Unsafe: D10_Unsafe :: Char -> D10
+ D10.Char.Unsafe: instance GHC.Classes.Eq D10.Char.Unsafe.D10
+ D10.Char.Unsafe: instance GHC.Classes.Ord D10.Char.Unsafe.D10
+ D10.Char.Unsafe: instance GHC.Enum.Bounded D10.Char.Unsafe.D10
+ D10.Char.Unsafe: instance GHC.Enum.Enum D10.Char.Unsafe.D10
+ D10.Char.Unsafe: instance GHC.Show.Show D10.Char.Unsafe.D10
+ D10.Char.Unsafe: newtype D10
+ D10.Num: charD10Either :: Num a => Char -> Either String (D10 a)
+ D10.Num: charD10Fail :: (Num a, MonadFail m) => Char -> m (D10 a)
+ D10.Num: charD10Maybe :: Num a => Char -> Maybe (D10 a)
+ D10.Num: d10 :: QuasiQuoter
+ D10.Num: d10Char :: Integral a => D10 a -> Char
+ D10.Num: d10Exp :: Integer -> Q Exp
+ D10.Num: d10Int :: Integral a => D10 a -> Int
+ D10.Num: d10Integer :: Integral a => D10 a -> Integer
+ D10.Num: d10ListExp :: String -> Q Exp
+ D10.Num: d10ListPat :: String -> Q Pat
+ D10.Num: d10Nat :: Integral a => D10 a -> Natural
+ D10.Num: d10Num :: (Integral b, Num a) => D10 b -> a
+ D10.Num: d10Pat :: Integer -> Q Pat
+ D10.Num: d10Str :: Integral a => D10 a -> String
+ D10.Num: d10list :: QuasiQuoter
+ D10.Num: data D10 a
+ D10.Num: intD10Either :: Num a => Int -> Either String (D10 a)
+ D10.Num: intD10Fail :: (Num a, MonadFail m) => Int -> m (D10 a)
+ D10.Num: intD10Maybe :: Num a => Int -> Maybe (D10 a)
+ D10.Num: intMod10 :: Num a => Int -> D10 a
+ D10.Num: integerD10Either :: Num a => Integer -> Either String (D10 a)
+ D10.Num: integerD10Fail :: (Num a, MonadFail m) => Integer -> m (D10 a)
+ D10.Num: integerD10Maybe :: Num a => Integer -> Maybe (D10 a)
+ D10.Num: integerMod10 :: Num a => Integer -> D10 a
+ D10.Num: integralD10Either :: (Num b, Integral a) => a -> Either String (D10 b)
+ D10.Num: integralD10Fail :: (Num b, Integral a, MonadFail m) => a -> m (D10 b)
+ D10.Num: integralD10Maybe :: (Num b, Integral a) => a -> Maybe (D10 b)
+ D10.Num: integralMod10 :: (Num b, Integral a) => a -> D10 b
+ D10.Num: natD10Either :: Num a => Natural -> Either String (D10 a)
+ D10.Num: natD10Fail :: (Num a, MonadFail m) => Natural -> m (D10 a)
+ D10.Num: natD10Maybe :: Num a => Natural -> Maybe (D10 a)
+ D10.Num: natMod10 :: Num a => Natural -> D10 a
+ D10.Num: strD10Either :: Num a => String -> Either String (D10 a)
+ D10.Num: strD10Fail :: (Num a, MonadFail m) => String -> m (D10 a)
+ D10.Num: strD10ListEither :: Num a => String -> Either String [D10 a]
+ D10.Num: strD10ListFail :: (Num a, MonadFail m) => String -> m [D10 a]
+ D10.Num: strD10ListMaybe :: Num a => String -> Maybe [D10 a]
+ D10.Num: strD10Maybe :: Num a => String -> Maybe (D10 a)
+ D10.Num.Arithmetic: (*) :: Integral a => D10 a -> D10 a -> D10 a
+ D10.Num.Arithmetic: (+) :: Integral a => D10 a -> D10 a -> D10 a
+ D10.Num.Arithmetic: (-) :: Integral a => D10 a -> D10 a -> D10 a
+ D10.Num.Conversions: charD10Either :: Num a => Char -> Either String (D10 a)
+ D10.Num.Conversions: charD10Fail :: (Num a, MonadFail m) => Char -> m (D10 a)
+ D10.Num.Conversions: charD10Maybe :: Num a => Char -> Maybe (D10 a)
+ D10.Num.Conversions: d10Char :: Integral a => D10 a -> Char
+ D10.Num.Conversions: d10Int :: Integral a => D10 a -> Int
+ D10.Num.Conversions: d10Integer :: Integral a => D10 a -> Integer
+ D10.Num.Conversions: d10Nat :: Integral a => D10 a -> Natural
+ D10.Num.Conversions: d10Num :: (Integral b, Num a) => D10 b -> a
+ D10.Num.Conversions: d10Str :: Integral a => D10 a -> String
+ D10.Num.Conversions: intD10Either :: Num a => Int -> Either String (D10 a)
+ D10.Num.Conversions: intD10Fail :: (Num a, MonadFail m) => Int -> m (D10 a)
+ D10.Num.Conversions: intD10Maybe :: Num a => Int -> Maybe (D10 a)
+ D10.Num.Conversions: intMod10 :: Num a => Int -> D10 a
+ D10.Num.Conversions: integerD10Either :: Num a => Integer -> Either String (D10 a)
+ D10.Num.Conversions: integerD10Fail :: (Num a, MonadFail m) => Integer -> m (D10 a)
+ D10.Num.Conversions: integerD10Maybe :: Num a => Integer -> Maybe (D10 a)
+ D10.Num.Conversions: integerMod10 :: Num a => Integer -> D10 a
+ D10.Num.Conversions: integralD10Either :: (Num b, Integral a) => a -> Either String (D10 b)
+ D10.Num.Conversions: integralD10Fail :: (Num b, Integral a, MonadFail m) => a -> m (D10 b)
+ D10.Num.Conversions: integralD10Maybe :: (Num b, Integral a) => a -> Maybe (D10 b)
+ D10.Num.Conversions: integralMod10 :: (Num b, Integral a) => a -> D10 b
+ D10.Num.Conversions: natD10Either :: Num a => Natural -> Either String (D10 a)
+ D10.Num.Conversions: natD10Fail :: (Num a, MonadFail m) => Natural -> m (D10 a)
+ D10.Num.Conversions: natD10Maybe :: Num a => Natural -> Maybe (D10 a)
+ D10.Num.Conversions: natMod10 :: Num a => Natural -> D10 a
+ D10.Num.Conversions: strD10Either :: Num a => String -> Either String (D10 a)
+ D10.Num.Conversions: strD10Fail :: (Num a, MonadFail m) => String -> m (D10 a)
+ D10.Num.Conversions: strD10ListEither :: Num a => String -> Either String [D10 a]
+ D10.Num.Conversions: strD10ListFail :: (Num a, MonadFail m) => String -> m [D10 a]
+ D10.Num.Conversions: strD10ListMaybe :: Num a => String -> Maybe [D10 a]
+ D10.Num.Conversions: strD10Maybe :: Num a => String -> Maybe (D10 a)
+ D10.Num.Quotes: d10 :: QuasiQuoter
+ D10.Num.Quotes: d10list :: QuasiQuoter
+ D10.Num.Splices: d10Exp :: Integer -> Q Exp
+ D10.Num.Splices: d10ListExp :: String -> Q Exp
+ D10.Num.Splices: d10ListPat :: String -> Q Pat
+ D10.Num.Splices: d10Pat :: Integer -> Q Pat
+ D10.Num.Type: data D10 a
+ D10.Num.Unsafe: D10_Unsafe :: a -> D10 a
+ D10.Num.Unsafe: instance GHC.Classes.Eq a => GHC.Classes.Eq (D10.Num.Unsafe.D10 a)
+ D10.Num.Unsafe: instance GHC.Classes.Ord a => GHC.Classes.Ord (D10.Num.Unsafe.D10 a)
+ D10.Num.Unsafe: instance GHC.Num.Num a => GHC.Enum.Bounded (D10.Num.Unsafe.D10 a)
+ D10.Num.Unsafe: instance GHC.Real.Integral a => GHC.Enum.Enum (D10.Num.Unsafe.D10 a)
+ D10.Num.Unsafe: instance GHC.Real.Integral a => GHC.Show.Show (D10.Num.Unsafe.D10 a)
+ D10.Num.Unsafe: newtype D10 a
+ D10.Predicate: isD10Char :: Char -> Bool
+ D10.Predicate: isD10Int :: Int -> Bool
+ D10.Predicate: isD10Integer :: Integer -> Bool
+ D10.Predicate: isD10Integral :: Integral a => a -> Bool
+ D10.Predicate: isD10ListStr :: String -> Bool
+ D10.Predicate: isD10Nat :: Natural -> Bool
+ D10.Predicate: isD10Str :: String -> Bool
+ D10.Safe: D0 :: D10
+ D10.Safe: D1 :: D10
+ D10.Safe: D2 :: D10
+ D10.Safe: D3 :: D10
+ D10.Safe: D4 :: D10
+ D10.Safe: D5 :: D10
+ D10.Safe: D6 :: D10
+ D10.Safe: D7 :: D10
+ D10.Safe: D8 :: D10
+ D10.Safe: D9 :: D10
+ D10.Safe: charD10Either :: Char -> Either String D10
+ D10.Safe: charD10Fail :: MonadFail m => Char -> m D10
+ D10.Safe: charD10Maybe :: Char -> Maybe D10
+ D10.Safe: d10Char :: D10 -> Char
+ D10.Safe: d10Int :: D10 -> Int
+ D10.Safe: d10Integer :: D10 -> Integer
+ D10.Safe: d10ListExp :: String -> Q Exp
+ D10.Safe: d10ListPat :: String -> Q Pat
+ D10.Safe: d10Nat :: D10 -> Natural
+ D10.Safe: d10Num :: Num a => D10 -> a
+ D10.Safe: d10Str :: D10 -> String
+ D10.Safe: d10list :: QuasiQuoter
+ D10.Safe: data D10
+ D10.Safe: intD10Either :: Int -> Either String D10
+ D10.Safe: intD10Fail :: MonadFail m => Int -> m D10
+ D10.Safe: intD10Maybe :: Int -> Maybe D10
+ D10.Safe: intMod10 :: Int -> D10
+ D10.Safe: integerD10Either :: Integer -> Either String D10
+ D10.Safe: integerD10Fail :: MonadFail m => Integer -> m D10
+ D10.Safe: integerD10Maybe :: Integer -> Maybe D10
+ D10.Safe: integerMod10 :: Integer -> D10
+ D10.Safe: integralD10Either :: Integral a => a -> Either String D10
+ D10.Safe: integralD10Fail :: (Integral a, MonadFail m) => a -> m D10
+ D10.Safe: integralD10Maybe :: Integral a => a -> Maybe D10
+ D10.Safe: integralMod10 :: Integral a => a -> D10
+ D10.Safe: natD10Either :: Natural -> Either String D10
+ D10.Safe: natD10Fail :: MonadFail m => Natural -> m D10
+ D10.Safe: natD10Maybe :: Natural -> Maybe D10
+ D10.Safe: natMod10 :: Natural -> D10
+ D10.Safe: strD10Either :: String -> Either String D10
+ D10.Safe: strD10Fail :: MonadFail m => String -> m D10
+ D10.Safe: strD10ListEither :: String -> Either String [D10]
+ D10.Safe: strD10ListFail :: MonadFail m => String -> m [D10]
+ D10.Safe: strD10ListMaybe :: String -> Maybe [D10]
+ D10.Safe: strD10Maybe :: String -> Maybe D10
+ D10.Safe.Arithmetic: (*) :: D10 -> D10 -> D10
+ D10.Safe.Arithmetic: (+) :: D10 -> D10 -> D10
+ D10.Safe.Arithmetic: (-) :: D10 -> D10 -> D10
+ D10.Safe.Conversions: charD10Either :: Char -> Either String D10
+ D10.Safe.Conversions: charD10Fail :: MonadFail m => Char -> m D10
+ D10.Safe.Conversions: charD10Maybe :: Char -> Maybe D10
+ D10.Safe.Conversions: d10Char :: D10 -> Char
+ D10.Safe.Conversions: d10Int :: D10 -> Int
+ D10.Safe.Conversions: d10Integer :: D10 -> Integer
+ D10.Safe.Conversions: d10Nat :: D10 -> Natural
+ D10.Safe.Conversions: d10Num :: Num a => D10 -> a
+ D10.Safe.Conversions: d10Str :: D10 -> String
+ D10.Safe.Conversions: intD10Either :: Int -> Either String D10
+ D10.Safe.Conversions: intD10Fail :: MonadFail m => Int -> m D10
+ D10.Safe.Conversions: intD10Maybe :: Int -> Maybe D10
+ D10.Safe.Conversions: intMod10 :: Int -> D10
+ D10.Safe.Conversions: integerD10Either :: Integer -> Either String D10
+ D10.Safe.Conversions: integerD10Fail :: MonadFail m => Integer -> m D10
+ D10.Safe.Conversions: integerD10Maybe :: Integer -> Maybe D10
+ D10.Safe.Conversions: integerMod10 :: Integer -> D10
+ D10.Safe.Conversions: integralD10Either :: Integral a => a -> Either String D10
+ D10.Safe.Conversions: integralD10Fail :: (Integral a, MonadFail m) => a -> m D10
+ D10.Safe.Conversions: integralD10Maybe :: Integral a => a -> Maybe D10
+ D10.Safe.Conversions: integralMod10 :: Integral a => a -> D10
+ D10.Safe.Conversions: natD10Either :: Natural -> Either String D10
+ D10.Safe.Conversions: natD10Fail :: MonadFail m => Natural -> m D10
+ D10.Safe.Conversions: natD10Maybe :: Natural -> Maybe D10
+ D10.Safe.Conversions: natMod10 :: Natural -> D10
+ D10.Safe.Conversions: strD10Either :: String -> Either String D10
+ D10.Safe.Conversions: strD10Fail :: MonadFail m => String -> m D10
+ D10.Safe.Conversions: strD10ListEither :: String -> Either String [D10]
+ D10.Safe.Conversions: strD10ListFail :: MonadFail m => String -> m [D10]
+ D10.Safe.Conversions: strD10ListMaybe :: String -> Maybe [D10]
+ D10.Safe.Conversions: strD10Maybe :: String -> Maybe D10
+ D10.Safe.Quotes: d10list :: QuasiQuoter
+ D10.Safe.Splices: d10ListExp :: String -> Q Exp
+ D10.Safe.Splices: d10ListPat :: String -> Q Pat
+ D10.Safe.Type: D0 :: D10
+ D10.Safe.Type: D1 :: D10
+ D10.Safe.Type: D2 :: D10
+ D10.Safe.Type: D3 :: D10
+ D10.Safe.Type: D4 :: D10
+ D10.Safe.Type: D5 :: D10
+ D10.Safe.Type: D6 :: D10
+ D10.Safe.Type: D7 :: D10
+ D10.Safe.Type: D8 :: D10
+ D10.Safe.Type: D9 :: D10
+ D10.Safe.Type: data D10
+ D10.Safe.Type: instance Data.Data.Data D10.Safe.Type.D10
+ D10.Safe.Type: instance GHC.Classes.Eq D10.Safe.Type.D10
+ D10.Safe.Type: instance GHC.Classes.Ord D10.Safe.Type.D10
+ D10.Safe.Type: instance GHC.Enum.Bounded D10.Safe.Type.D10
+ D10.Safe.Type: instance GHC.Enum.Enum D10.Safe.Type.D10
+ D10.Safe.Type: instance GHC.Generics.Generic D10.Safe.Type.D10
+ D10.Safe.Type: instance GHC.Show.Show D10.Safe.Type.D10

Files

CHANGELOG.md view
@@ -97,3 +97,47 @@ **v0.3.0.1**    * Support GHC 9.0, base 4.15, template-haskell 2.17++**v1**++Removed the `Data` prefix from module names.++  * `Data.D10.Char` is now `D10.Char`+  * `Data.D10.Num` is now `D10.Num`+  * `Data.D10.Predicate` is now `D10.Predicate`+  * `Data.D10.Safe` is now `D10.Safe`++Constructors for `D10` are no longer exported by the modules formerly+known as `Data.D10.Char` and `Data.D10.Num`. They have moved to the+new modules `D10.Char.Unsafe` and `D10.Num.Unsafe` respectively.++Operators `(+)`, `(-)`, and `(*)` have been moved into their own+separate modules, as the names conflict with `Prelude` functions.+These new modules are:++  * `D10.Char.Arithmetic`+  * `D10.Num.Arithmetic`+  * `D10.Safe.Arithmetic`++Other new modules:++  * `D10.Char.Conversions`+  * `D10.Char.Quotes`+  * `D10.Char.Splices`+  * `D10.Char.Type`+  * `D10.Num.Conversions`+  * `D10.Num.Quotes`+  * `D10.Num.Splices`+  * `D10.Num.Type`+  * `D10.Safe.Conversions`+  * `D10.Safe.Quotes`+  * `D10.Safe.Splices`+  * `D10.Safe.Type`++All instances of the `Language.Haskell.TH.Syntax.Lift` class+have been removed++Added *Safe Haskell* language flags (`Safe`, `Trustworthy`, `Unsafe`)+to indicate which modules permit constructing invalid values++Required Cabal version required is raised from 2.2 to 3.0
README.md view
@@ -4,36 +4,12 @@  ## Modules -Each of the following modules defines a different type named-`D10`, all of which are different representations of the same-concept:--* `Data.D10.Char` - Defines a `D10` type as a newtype for `Char`,-  where the values are restricted to characters between `'0'` and-  `'9'`.-* `Data.D10.Num` - Defines a `D10` type as a newtype for any-  type with an instance of the `Num` class, where the values-  are restricted to numbers between `fromInteger 0` and-  `fromInteger 9`.-* `Data.D10.Safe` - Defines a `D10` type as-  `D0 | D1 | D2 | ... | D9`.--Other modules:+Each of the following modules defines a different type named `D10`, all of which are different representations of the same concept: -* `Data.D10.Predicate` - Functions to test whether values of-  various types represent digits in the range *0* to *9*.+* `D10.Char` - Defines a `D10` type as a newtype for `Char`, where the values are restricted to characters between `'0'` and `'9'`.+* `D10.Num` - Defines a `D10` type as a newtype for any type with an instance of the `Num` class, where the values are restricted to numbers between `fromInteger 0` and `fromInteger 9`.+* `D10.Safe` - Defines a `D10` type as `D0 | D1 | D2 | ... | D9`.  ## Quasi-quoters -Each module that defines a `D10` type also defines quasi-quoters-for it. With the `QuasiQuotes` GHC extension enabled, a single-digit like *7* can be written as `[d10|7|]`, and a list of digits-like *[4,5,6]* can be written as `[d10|456|]`. For `Data.D10.Char`-and `Data.D10.Num`, the quasi-quoters are an important feature,-because the `D10` types defined in these modules have unsafe-constructors, and the quasi-quoters provide compile-time assurance-that we never construct a `D10` that represents a value outside-the range *0* to *9*. For `Data.D10.Safe`, the quasi-quoter is-offered merely as a possible convenience, allowing you to write-`[d10|456789|]` in place of the somewhat longer expression-`[D4,D5,D6,D7,D8,D9]`.+Each module that defines a `D10` type also defines quasi-quoters for it. With the `QuasiQuotes` GHC extension enabled, a single digit like *7* can be written as `[d10|7|]`, and a list of digits like *[4,5,6]* can be written as `[d10|456|]`. For `D10.Char` and `D10.Num`, the quasi-quoters are an important feature, because the `D10` types defined in these modules have unsafe constructors, and the quasi-quoters provide compile-time assurance that we never construct a `D10` that represents a value outside the range *0* to *9*.
d10.cabal view
@@ -1,49 +1,59 @@-cabal-version: 2.2+cabal-version: 3.0  name: d10-version: 0.3.0.1+version: 1 category: Data synopsis: Digits 0-9  description:     Data types representing the digits zero through nine.-    .+     == Modules-    .+     Each of the following modules defines a different type named     @D10@, all of which are different representations of the same     concept:-    .-    * "Data.D10.Char" - Defines a @D10@ type as a newtype for @Char@,-      where the values are restricted to characters between @'0'@ and-      @'9'@.-    * "Data.D10.Num" - Defines a @D10@ type as a newtype for any++    * "D10.Char" - Defines a @D10@ type as a newtype for @Char@,+      where the values are restricted to characters between+      @'0'@ and @'9'@+    * "D10.Num" - Defines a @D10@ type as a newtype for any       type with an instance of the @Num@ class, where the values       are restricted to numbers between @fromInteger 0@ and-      @fromInteger 9@.-    * "Data.D10.Safe" - Defines a @D10@ type as-      @D0 | D1 | D2 | ... | D9@.-    .-    Other modules:-    .-    * "Data.D10.Predicate" - Functions to test whether values of-      various types represent digits in the range /0/ to /9/.-    .+      @fromInteger 9@+    * "D10.Safe" - Defines a @D10@ type as @D0 | D1 | D2 | ... | D9@++    The @Arithmetic@ modules provide infix operators (@+@), (@-@), (@*@)+    for modular arithmetic:++    * "D10.Char.Arithmetic"+    * "D10.Num.Arithmetic"+    * "D10.Safe.Arithmetic"++    The following modules export constructors that can be used+    incorrectly:++    * "D10.Char.Unsafe"+    * "D10.Num.Unsafe"++    Functions to test whether values of various types represent+    digits in the range 0 to 9:++    * "D10.Predicate"+     == Quasi-quoters-    .-    Each module that defines a @D10@ type also defines quasi-quoters-    for it. With the @QuasiQuotes@ GHC extension enabled, a single-    digit like /7/ can be written as @[d10|7|]@, and a list of digits-    like /[4,5,6]/ can be written as @[d10|456|]@. For "Data.D10.Char"-    and "Data.D10.Num", the quasi-quoters are an important feature,-    because the @D10@ types defined in these modules have unsafe-    constructors, and the quasi-quoters provide compile-time assurance-    that we never construct a @D10@ that represents a value outside-    the range /0/ to /9/. For "Data.D10.Safe", the quasi-quoter is-    offered merely as a possible convenience, allowing you to write-    @[d10|456789|]@ in place of the somewhat longer expression-    @[D4,D5,D6,D7,D8,D9]@. +    * The "D10.Char" and "D10.Num" modules include quasi-quoters+      named @d10@ used to express single digits. For example, 7+      can be written as @[d10|7|]@. This is an important feature+      because the @D10@ types defined in these modules have+      unsafe constructors, and the quasi-quoters provide+      compile-time assurance that we never construct a @D10@+      that represents a value outside the range 0 to 9.+    * "D10.Char", "D10.Num", and "D10.Safe" include quasi-quoters+      named @d10list@ to express lists of digits. For example,+      [4, 5, 6] can be written as @[d10list|456|]@.+ homepage:    https://github.com/typeclasses/d10 bug-reports: https://github.com/typeclasses/d10/issues @@ -57,143 +67,80 @@ build-type: Simple  tested-with:-    GHC == 8.2.2-  , GHC == 8.4.3-  , GHC == 8.6.1-  , GHC == 8.8.1-  , GHC == 8.10.1-  , GHC == 9.0.1+    GHC == 8.2.2, GHC == 8.4.3, GHC == 8.6.1+  , GHC == 8.8.1, GHC == 8.10.1, GHC == 9.0.1  extra-source-files:     README.md     CHANGELOG.md  source-repository head-  type: git-  location: https://github.com/typeclasses/d10+    type: git+    location: https://github.com/typeclasses/d10 -library-  default-language: Haskell2010-  ghc-options: -Wall-  hs-source-dirs: src+common language+    default-language: Haskell2010+    ghc-options: -Wall+    default-extensions:+        DeriveDataTypeable DeriveGeneric DeriveLift+        DerivingStrategies InstanceSigs QuasiQuotes+        ScopedTypeVariables TypeApplications -  build-depends:-      base ^>= 4.10 || ^>= 4.11 || ^>= 4.12-        || ^>= 4.13 || ^>= 4.14 || ^>= 4.15-    , template-haskell-           ^>= 2.12 || ^>= 2.13 || ^>= 2.14-        || ^>= 2.15 || ^>= 2.16 || ^>= 2.17+common library-dependencies+    build-depends:+        base ^>= 4.10 || ^>= 4.11 || ^>= 4.12+          || ^>= 4.13 || ^>= 4.14 || ^>= 4.15+      , template-haskell+             ^>= 2.12 || ^>= 2.13 || ^>= 2.14+          || ^>= 2.15 || ^>= 2.16 || ^>= 2.17 -  exposed-modules:-      Data.D10.Char-    , Data.D10.Num-    , Data.D10.Predicate-    , Data.D10.Safe+common test+    import: language+    import: library-dependencies+    hs-source-dirs: test+    other-modules: AssertQFails Fallible+    build-depends: d10, hedgehog ^>= 1.0+    default-extensions: GeneralizedNewtypeDeriving+                        TemplateHaskell -  default-extensions:-      DeriveDataTypeable-      DeriveGeneric-      DeriveLift-      DerivingStrategies-      GeneralizedNewtypeDeriving-      InstanceSigs-      QuasiQuotes-      ScopedTypeVariables-      TemplateHaskell-      TypeApplications+library+    import: language+    import: library-dependencies+    hs-source-dirs: src+    exposed-modules:+        D10.Char+          , D10.Char.Arithmetic+          , D10.Char.Conversions+          , D10.Char.Quotes+          , D10.Char.Splices+          , D10.Char.Type+          , D10.Char.Unsafe+      , D10.Num+          , D10.Num.Arithmetic+          , D10.Num.Conversions+          , D10.Num.Quotes+          , D10.Num.Splices+          , D10.Num.Type+          , D10.Num.Unsafe+      , D10.Safe+          , D10.Safe.Arithmetic+          , D10.Safe.Conversions+          , D10.Safe.Quotes+          , D10.Safe.Splices+          , D10.Safe.Type+      , D10.Predicate  test-suite char-  default-language: Haskell2010-  ghc-options: -Wall-  hs-source-dirs: test-  type: exitcode-stdio-1.0-  main-is: char.hs--  other-modules:-      AssertQFails-      Fallible--  build-depends:-      d10-    , base ^>= 4.10 || ^>= 4.11 || ^>= 4.12-        || ^>= 4.13 || ^>= 4.14 || ^>= 4.15-    , hedgehog ^>= 1.0-    , template-haskell-           ^>= 2.12 || ^>= 2.13 || ^>= 2.14-        || ^>= 2.15 || ^>= 2.16 || ^>= 2.17--  default-extensions:-      DeriveDataTypeable-      DeriveGeneric-      DeriveLift-      DerivingStrategies-      GeneralizedNewtypeDeriving-      InstanceSigs-      QuasiQuotes-      ScopedTypeVariables-      TemplateHaskell-      TypeApplications+    import: test+    type: exitcode-stdio-1.0+    main-is: char.hs  test-suite num-  default-language: Haskell2010-  ghc-options: -Wall-  hs-source-dirs: test-  type: exitcode-stdio-1.0-  main-is: num.hs--  other-modules:-      AssertQFails-      Fallible--  build-depends:-      d10-    , base ^>= 4.10 || ^>= 4.11 || ^>= 4.12-        || ^>= 4.13 || ^>= 4.14 || ^>= 4.15-    , hedgehog ^>= 1.0-    , template-haskell-           ^>= 2.12 || ^>= 2.13 || ^>= 2.14-        || ^>= 2.15 || ^>= 2.16 || ^>= 2.17--  default-extensions:-      DeriveDataTypeable-      DeriveGeneric-      DeriveLift-      DerivingStrategies-      GeneralizedNewtypeDeriving-      InstanceSigs-      QuasiQuotes-      ScopedTypeVariables-      TemplateHaskell-      TypeApplications+    import: test+    type: exitcode-stdio-1.0+    main-is: num.hs  test-suite safe-  default-language: Haskell2010-  ghc-options: -Wall-  hs-source-dirs: test-  type: exitcode-stdio-1.0-  main-is: safe.hs--  other-modules:-      AssertQFails-      Fallible--  build-depends:-      d10-    , base ^>= 4.10 || ^>= 4.11 || ^>= 4.12-        || ^>= 4.13 || ^>= 4.14 || ^>= 4.15-    , hedgehog ^>= 1.0-    , template-haskell-           ^>= 2.12 || ^>= 2.13 || ^>= 2.14-        || ^>= 2.15 || ^>= 2.16 || ^>= 2.17--  default-extensions:-      DeriveDataTypeable-      DeriveGeneric-      DeriveLift-      DerivingStrategies-      GeneralizedNewtypeDeriving-      InstanceSigs-      QuasiQuotes-      ScopedTypeVariables-      TemplateHaskell-      TypeApplications+    import: test+    type: exitcode-stdio-1.0+    main-is: safe.hs
+ src/D10/Char.hs view
@@ -0,0 +1,132 @@+{-# language Safe #-}++{- |++Defines a 'D10' type as a newtype for 'Char', where the+values are restricted to characters between @'0'@ and @'9'@.++This module provides many functions for constructing 'D10'+values, including:++  * @'integerD10Maybe' :: 'Integer' -> 'Maybe' 'D10'@+  * @'integerMod10' :: 'Integer' -> 'D10'@++With the @QuasiQuotes@ GHC extension enabled, you can write+'D10' literals using the quasi-quoters 'd10' and 'd10list'.++-}++module D10.Char+    (+    -- * Related modules+    -- $modules++    -- * Type+      D10++    -- ** Bounded+    -- $bounded++    -- ** Enum+    -- $enum++    -- ** Show+    -- $show++    -- * Quasi-quoters+    , d10, d10list++    -- * Splices+    -- ** Expressions+    , d10Exp, d10ListExp+    -- ** Patterns+    , d10Pat, d10ListPat++    -- * Conversions+    -- ** D10 / Char+    , d10Char, charD10Maybe, charD10Either, charD10Fail+    -- ** D10 / String+    , d10Str, strD10Maybe, strD10Either, strD10Fail+    -- ** [D10] / String+    , strD10ListMaybe, strD10ListEither, strD10ListFail+    -- ** D10 / Natural+    , d10Nat, natD10Maybe, natD10Either, natD10Fail+    , natMod10+    -- ** D10 / Integer+    , d10Integer, integerD10Maybe, integerD10Either+    , integerD10Fail, integerMod10+    -- ** D10 / Int+    , d10Int, intD10Maybe, intD10Either+    , intD10Fail, intMod10+    -- ** D10 / general numeric types+    , d10Num, integralD10Maybe, integralD10Either+    , integralD10Fail, integralMod10++    ) where++import D10.Char.Conversions+import D10.Char.Type+import D10.Char.Splices+import D10.Char.Quotes++{- $modules++Additional functions related to this 'D10' type may be found in:++  * "D10.Char.Arithmetic"++The contents of the following modules are re-exported here:++  * "D10.Char.Conversions"+  * "D10.Char.Splices"+  * "D10.Char.Quotes"+  * "D10.Char.Type"++The unsafe constructor for 'D10' can be found in:++  * "D10.Char.Unsafe"++The following modules define @D10@ types in different ways+but are otherwise very similar to this one:++  * "D10.Num"+  * "D10.Safe"++-}++{- $bounded++>>> minBound :: D10+[d10|0|]++>>> maxBound :: D10+[d10|9|]++-}++{- $enum++>>> [ [d10|5|] .. ]+[d10list|56789|]++>>> [ [d10|4|] .. [d10|7|] ]+[d10list|4567|]++>>> [ [d10|5|], [d10|4|] .. ]+[d10list|543210|]++>>> [ [d10|1|], [d10|3|] .. ]+[d10list|13579|]++>>> [ minBound .. maxBound ] :: [D10]+[d10list|0123456789|]++-}++{- $show++'show' shows base-10 digits using the quasiquoters defined+in this module. A single digit is displayed using 'd10'.+A list of digits is displayed using 'd10list'.++-}
+ src/D10/Char/Arithmetic.hs view
@@ -0,0 +1,40 @@+{-# language Safe #-}++module D10.Char.Arithmetic where++import qualified Prelude as P++import D10.Char (D10, d10Int, intMod10)++-- | Addition modulo 10.+--+-- >>> [d10|2|] + [d10|3|]+-- [d10|5|]+--+-- >>> [d10|6|] + [d10|7|]+-- [d10|3|]++(+) :: D10 -> D10 -> D10+x + y = intMod10 (d10Int x P.+ d10Int y)++-- | Subtraction modulo 10.+--+-- >>> [d10|7|] - [d10|5|]+-- [d10|2|]+--+-- >>> [d10|3|] - [d10|7|]+-- [d10|6|]++(-) :: D10 -> D10 -> D10+x - y = intMod10 (d10Int x P.- d10Int y)++-- | Multiplication modulo 10.+--+-- >>> [d10|2|] * [d10|4|]+-- [d10|8|]+--+-- >>> [d10|7|] * [d10|8|]+-- [d10|6|]++(*) :: D10 -> D10 -> D10+x * y = intMod10 (d10Int x P.* d10Int y)
+ src/D10/Char/Conversions.hs view
@@ -0,0 +1,547 @@+{-# language Trustworthy #-}++module D10.Char.Conversions+    (+    -- * D10 / Char+      d10Char, charD10Maybe, charD10Either, charD10Fail+    -- * D10 / String+    , d10Str, strD10Maybe, strD10Either, strD10Fail+    -- * [D10] / String+    , strD10ListMaybe, strD10ListEither, strD10ListFail+    -- * D10 / Natural+    , d10Nat, natD10Maybe, natD10Either, natD10Fail+    , natMod10+    -- * D10 / Integer+    , d10Integer, integerD10Maybe, integerD10Either+    , integerD10Fail, integerMod10+    -- * D10 / Int+    , d10Int, intD10Maybe, intD10Either+    , intD10Fail, intMod10+    -- * D10 / general numeric types+    , d10Num, integralD10Maybe, integralD10Either+    , integralD10Fail, integralMod10+    ) where++import D10.Char.Unsafe (D10(..))+import D10.Predicate (isD10Char, isD10Int, isD10Integer, isD10Nat)++-- base+import Control.Monad.Fail (MonadFail (fail))+import Data.Char          (chr, ord)+import Numeric.Natural    (Natural)+import Prelude            hiding (fail)++import qualified Prelude as P++-- | Convert a 'D10' to its underlying 'Char' representation.+--+-- >>> d10Char [d10|7|]+-- '7'++d10Char :: D10 -> Char+d10Char (D10_Unsafe x) = x++-- | Convert a 'D10' to a 'String'.+--+-- @'d10Str' x = ['d10Char' x]@+--+-- >>> d10Str [d10|7|]+-- "7"++d10Str :: D10 -> String+d10Str (D10_Unsafe x) = [x]++-- | Convert a 'D10' to a 'Natural'.+--+-- 'd10Num' is a more general version of this function.+--+-- >>> d10Nat [d10|7|]+-- 7++d10Nat :: D10 -> Natural+d10Nat (D10_Unsafe x) = fromIntegral (ord x P.- ord '0')++-- | Convert a 'D10' to an 'Integer'.+--+-- 'd10Num' is a more general version of this function.+--+-- >>> d10Integer [d10|7|]+-- 7++d10Integer :: D10 -> Integer+d10Integer (D10_Unsafe x) = toInteger (ord x P.- ord '0')++-- | Convert a 'D10' to an 'Int'.+--+-- 'd10Num' is a more general version of this function.+--+-- >>> d10Int [d10|7|]+-- 7++d10Int :: D10 -> Int+d10Int (D10_Unsafe x) = ord x P.- ord '0'++-- | Convert a 'D10' to any kind of number with a 'Num' instance.+--+-- Specialized versions of this function include 'd10Nat',+-- 'd10Integer', and 'd10Int'.+--+-- >>> d10Num [d10|7|] :: Integer+-- 7++d10Num :: Num a => D10 -> a+d10Num (D10_Unsafe x) = fromIntegral (ord x P.- ord '0')++---------------------------------------------------++-- | The 'D10' which is uniquely congruent modulo 10 to the given 'Natural'.+--+-- 'integralMod10' is a more general version of this function.+--+-- >>> natMod10 56+-- [d10|6|]++natMod10 :: Natural -> D10+natMod10 x = D10_Unsafe (chr (ord '0' P.+ fromIntegral (x `mod` 10)))++-- | The 'D10' which is uniquely congruent modulo 10 to the given 'Integer'.+--+-- 'integralMod10' is a more general version of this function.+--+-- >>> integerMod10 56+-- [d10|6|]+--+-- >>> integerMod10 (-56)+-- [d10|4|]++integerMod10 :: Integer -> D10+integerMod10 x = D10_Unsafe (chr (ord '0' P.+ fromInteger (x `mod` 10)))++-- | The 'D10' which is uniquely congruent modulo 10 to the given 'Int'.+--+-- 'integralMod10' is a more general version of this function.+--+-- >>> intMod10 56+-- [d10|6|]+--+-- >>> intMod10 (-56)+-- [d10|4|]++intMod10 :: Int -> D10+intMod10 x = D10_Unsafe (chr (ord '0' P.+ (x `mod` 10)))++-- | The 'D10' which is uniquely congruent modulo 10 to the given number+-- (whose type must have an instance of the 'Integral' class).+--+-- Specialized versions of this function include 'natMod10',+-- 'integerMod10', and 'intMod10'.+--+-- >>> integralMod10 (56 :: Integer)+-- [d10|6|]+--+-- >>> integralMod10 ((-56) :: Integer)+-- [d10|4|]++integralMod10 :: Integral a => a -> D10+integralMod10 x = D10_Unsafe (chr (ord '0' P.+ fromIntegral (x `mod` 10)))++---------------------------------------------------++-- | Convert a 'Char' to a 'D10' if it is within the range+-- @'0'@ to @'9'@, or produce 'Nothing' otherwise.+--+-- @'D10.Predicate.isD10Char' x = 'Data.Maybe.isJust' ('charD10Maybe' x)@+--+-- 'charD10Fail' is a more general version of this function.+--+-- >>> charD10Maybe '5'+-- Just [d10|5|]+--+-- >>> charD10Maybe 'a'+-- Nothing++charD10Maybe :: Char -> Maybe D10+charD10Maybe x+        | isD10Char x  =  Just (D10_Unsafe x)+        | otherwise    =  Nothing++-- | Convert a 'String' to a 'D10' if it consists of exactly one+-- character and that character is within the range @'0'@ to @'9'@,+-- or produce 'Nothing' otherwise.+--+-- @'D10.Predicate.isD10Str' x = 'Data.Maybe.isJust' ('strD10Maybe' x)@+--+-- 'strD10Fail' is a more general version of this function.+--+-- >>> strD10Maybe "5"+-- Just [d10|5|]+--+-- >>> strD10Maybe "a"+-- Nothing+--+-- >>> strD10Maybe "58"+-- Nothing++strD10Maybe :: String -> Maybe D10+strD10Maybe [x] = charD10Maybe x+strD10Maybe _   = Nothing++-- | Convert a 'String' to a list of 'D10' if all of the characters+-- in the string are within the range @'0'@ to @'9'@, or produce+-- 'Nothing' otherwise.+--+-- @'D10.Predicate.isD10ListStr' x = 'Data.Maybe.isJust' ('strD10ListMaybe' x)@+--+-- 'strD10ListFail' is a more general version of this function.+--+-- >>> strD10ListMaybe "5"+-- Just [d10list|5|]+--+-- >>> strD10ListMaybe "a"+-- Nothing+--+-- >>> strD10ListMaybe "58"+-- Just [d10list|58|]++strD10ListMaybe :: String -> Maybe [D10]+strD10ListMaybe = traverse charD10Maybe++-- | Convert a 'Natural' to a 'D10' if it is less than 10,+-- or produce 'Nothing' otherwise.+--+-- @'D10.Predicate.isD10Nat' x = 'Data.Maybe.isJust' ('natD10Maybe' x)@+--+-- 'integralD10Maybe', 'natD10Fail', and 'integralD10Fail'+-- are more general versions of this function.+--+-- >>> natD10Maybe 5+-- Just [d10|5|]+--+-- >>> natD10Maybe 12+-- Nothing++natD10Maybe :: Natural -> Maybe D10+natD10Maybe x+        | isD10Nat x  =  Just (D10_Unsafe (chr (fromIntegral x P.+ ord '0')))+        | otherwise   =  Nothing++-- | Convert an 'Integer' to a 'D10' if it is within the range 0 to 9,+-- or produce 'Nothing' otherwise.+--+-- @'D10.Predicate.isD10Integer' x = 'Data.Maybe.isJust' ('integerD10Maybe' x)@+--+-- 'integralD10Maybe', 'integerD10Fail', and 'integralD10Fail'+-- are more general versions of this function.+--+-- >>> integerD10Maybe 5+-- Just [d10|5|]+--+-- >>> integerD10Maybe 12+-- Nothing+--+-- >>> integerD10Maybe (-5)+-- Nothing++integerD10Maybe :: Integer -> Maybe D10+integerD10Maybe x+        | isD10Integer x  =  Just (D10_Unsafe (chr (fromInteger x P.+ ord '0')))+        | otherwise       =  Nothing++-- | Convert an 'Int' to a 'D10' if it is within the range 0 to 9,+-- or produce 'Nothing' otherwise.+--+-- @'D10.Predicate.isD10Int' x = 'Data.Maybe.isJust' ('intD10Maybe' x)@+--+-- 'integralD10Maybe', 'intD10Fail', and 'integralD10Fail'+-- are more general versions of this function.+--+-- >>> intD10Maybe 5+-- Just [d10|5|]+--+-- >>> intD10Maybe 12+-- Nothing+--+-- >>> intD10Maybe (-5)+-- Nothing++intD10Maybe :: Int -> Maybe D10+intD10Maybe x+        | isD10Int x  =  Just (D10_Unsafe (chr (x P.+ ord '0')))+        | otherwise   =  Nothing++-- | Construct a 'D10' from any kind of number with an 'Integral'+-- instance, or produce 'Nothing' if the number falls outside the+-- range 0 to 9.+--+-- @'D10.Predicate.isD10Integral' x = 'Data.Maybe.isJust' ('integralD10Maybe' x)@+--+-- Specialized versions of this function include 'natD10Maybe',+-- 'integerD10Maybe', and 'intD10Maybe'.+--+-- 'integralD10Fail' is a more general version of this function.+--+-- >>> integralD10Maybe (5 :: Integer)+-- Just [d10|5|]+--+-- >>> integralD10Maybe (12 :: Integer)+-- Nothing+--+-- >>> integralD10Maybe ((-5) :: Integer)+-- Nothing++integralD10Maybe :: Integral a => a -> Maybe D10+integralD10Maybe x = integerD10Maybe (toInteger x)++---------------------------------------------------++-- | Convert a 'Char' to a 'D10' if it is within the range+-- @'0'@ to @'9'@, or 'Left' with an error message otherwise.+--+-- >>> charD10Either '5'+-- Right [d10|5|]+--+-- >>> charD10Either 'a'+-- Left "d10 must be between 0 and 9"++charD10Either :: Char -> Either String D10+charD10Either x+        | isD10Char x  =  Right (D10_Unsafe x)+        | otherwise    =  Left "d10 must be between 0 and 9"++-- | Convert a 'String' to a 'D10' if it consists of a single+-- character and that character is within the range @'0'@ to+-- @'9'@, or 'Left' with an error message otherwise.+--+-- >>> strD10Either "5"+-- Right [d10|5|]+--+-- >>> strD10Either "a"+-- Left "d10 must be between 0 and 9"+--+-- >>> strD10Either "58"+-- Left "d10 must be a single character"++strD10Either :: String -> Either String D10+strD10Either [x]         =  charD10Either x+strD10Either _           =  Left "d10 must be a single character"++-- | Convert a 'String' to a 'D10' if all of the characters in+-- the string fall within the range @'0'@ to @'9'@, or 'Left'+-- with an error message otherwise.+--+-- >>> strD10ListEither "5"+-- Right [d10list|5|]+--+-- >>> strD10ListEither "a"+-- Left "d10 must be between 0 and 9"+--+-- >>> strD10ListEither "58"+-- Right [d10list|58|]++strD10ListEither :: String -> Either String [D10]+strD10ListEither = traverse charD10Either++-- | Convert a 'Natural' to a 'D10' if it is less than 10,+-- or 'Left' with an error message otherwise.+--+-- >>> natD10Either 5+-- Right [d10|5|]+--+-- >>> natD10Either 12+-- Left "d10 must be less than 10"++natD10Either :: Natural -> Either String D10+natD10Either x =+    case (natD10Maybe x) of+        Just y  -> Right y+        Nothing -> Left "d10 must be less than 10"++-- | Convert an 'Integer' to a 'D10' if it is within the+-- range 0 to 9, or 'Left' with an error message otherwise.+--+-- >>> integerD10Either 5+-- Right [d10|5|]+--+-- >>> integerD10Either 12+-- Left "d10 must be between 0 and 9"+--+-- >>> integerD10Either (-5)+-- Left "d10 must be between 0 and 9"++integerD10Either :: Integer -> Either String D10+integerD10Either x =+    case (integerD10Maybe x) of+        Just y  -> Right y+        Nothing -> Left "d10 must be between 0 and 9"++-- | Convert an 'Int' to a 'D10' if it is within the range+-- 0 to 9, or 'Left' with an error message otherwise.+--+-- >>> intD10Either 5+-- Right [d10|5|]+--+-- >>> intD10Either 12+-- Left "d10 must be between 0 and 9"+--+-- >>> intD10Either (-5)+-- Left "d10 must be between 0 and 9"++intD10Either :: Int -> Either String D10+intD10Either x =+    case (intD10Maybe x) of+        Just y  ->  Right y+        Nothing ->  Left "d10 must be between 0 and 9"++-- | Convert a number of a type that has an 'Integral' instance+-- to a 'D10' if it falls within the range 0 to 9, or 'Left'+-- with an error message otherwise.+--+-- >>> integralD10Either (5 :: Integer)+-- Right [d10|5|]+--+-- >>> integralD10Either (12 :: Integer)+-- Left "d10 must be between 0 and 9"+--+-- >>> integralD10Either ((-5) :: Integer)+-- Left "d10 must be between 0 and 9"++integralD10Either :: Integral a => a -> Either String D10+integralD10Either x = integerD10Either (toInteger x)++---------------------------------------------------++-- | Convert a 'Char' to a 'D10' if it is within the range+-- @'0'@ to @'9'@, or 'fail' with an error message otherwise.+--+-- 'charD10Maybe' is a specialized version of this function.+--+-- >>> charD10Fail '5' :: IO D10+-- [d10|5|]+--+-- >>> charD10Fail 'a' :: IO D10+-- *** Exception: user error (d10 must be between 0 and 9)++charD10Fail :: MonadFail m => Char -> m D10+charD10Fail x+        | isD10Char x  =  return (D10_Unsafe x)+        | otherwise    =  fail "d10 must be between 0 and 9"++-- | Convert a 'String' to a 'D10' if it consists of a single+-- character and that character is within the range @'0'@ to+-- @'9'@, or 'fail' with an error message otherwise.+--+-- 'strD10Maybe' is a specialized version of this function.+--+-- >>> strD10Fail "5" :: IO D10+-- [d10|5|]+--+-- >>> strD10Fail "a" :: IO D10+-- *** Exception: user error (d10 must be between 0 and 9)+--+-- >>> strD10Fail "58" :: IO D10+-- *** Exception: user error (d10 must be a single character)++strD10Fail :: MonadFail m => String -> m D10+strD10Fail [x]         =  charD10Fail x+strD10Fail _           =  fail "d10 must be a single character"++-- | Convert a 'String' to a 'D10' if all of the characters in+-- the string fall within the range @'0'@ to @'9'@, or 'fail'+-- with an error message otherwise.+--+-- 'strD10ListMaybe' is a specialized version of this function.+--+-- >>> strD10ListFail "5" :: IO [D10]+-- [d10list|5|]+--+-- >>> strD10ListFail "a" :: IO [D10]+-- *** Exception: user error (d10 must be between 0 and 9)+--+-- >>> strD10ListFail "58" :: IO [D10]+-- [d10list|58|]++strD10ListFail :: MonadFail m => String -> m [D10]+strD10ListFail = traverse charD10Fail++-- | Convert a 'Natural' to a 'D10' if it is less than 10,+-- or 'fail' with an error message otherwise.+--+-- 'natD10Maybe' is a specialized version of this function.+--+-- 'integralD10Fail' is a more general version of this function.+--+-- >>> natD10Fail 5 :: IO D10+-- [d10|5|]+--+-- >>> natD10Fail 12 :: IO D10+-- *** Exception: user error (d10 must be less than 10)++natD10Fail :: MonadFail m => Natural -> m D10+natD10Fail x =+    case (natD10Maybe x) of+        Just y  -> return y+        Nothing -> fail "d10 must be less than 10"++-- | Convert an 'Integer' to a 'D10' if it is within the+-- range 0 to 9, or 'fail' with an error message otherwise.+--+-- 'integerD10Maybe' is a specialized version of this function.+--+-- 'integralD10Fail' is a more general version of this function.+--+-- >>> integerD10Fail 5 :: IO D10+-- [d10|5|]+--+-- >>> integerD10Fail 12 :: IO D10+-- *** Exception: user error (d10 must be between 0 and 9)+--+-- >>> integerD10Fail (-5) :: IO D10+-- *** Exception: user error (d10 must be between 0 and 9)++integerD10Fail :: MonadFail m => Integer -> m D10+integerD10Fail x =+    case (integerD10Maybe x) of+        Just y  -> return y+        Nothing -> fail "d10 must be between 0 and 9"++-- | Convert an 'Int' to a 'D10' if it is within the range+-- 0 to 9, or 'fail' with an error message otherwise.+--+-- 'intD10Maybe' is a specialized version of this function.+--+-- 'integralD10Fail' is a more general version of this function.+--+-- >>> intD10Fail 5 :: IO D10+-- [d10|5|]+--+-- >>> intD10Fail 12 :: IO D10+-- *** Exception: user error (d10 must be between 0 and 9)+--+-- >>> intD10Fail (-5) :: IO D10+-- *** Exception: user error (d10 must be between 0 and 9)++intD10Fail :: MonadFail m => Int -> m D10+intD10Fail x =+    case (intD10Maybe x) of+        Just y  ->  return y+        Nothing ->  fail "d10 must be between 0 and 9"++-- | Convert a number of a type that has an 'Integral' instance+-- to a 'D10' if it falls within the range 0 to 9, or 'fail'+-- with an error message otherwise.+--+-- 'natD10Maybe', 'integerD10Maybe', 'intD10Maybe',+-- 'integralD10Maybe', 'natD10Fail', 'integerD10Fail', and+-- 'intD10Fail' are all specialized versions of this function.+--+-- >>> integralD10Fail (5 :: Integer) :: IO D10+-- [d10|5|]+--+-- >>> integralD10Fail (12 :: Integer) :: IO D10+-- *** Exception: user error (d10 must be between 0 and 9)+--+-- >>> integralD10Fail ((-5) :: Integer) :: IO D10+-- *** Exception: user error (d10 must be between 0 and 9)++integralD10Fail :: (Integral a, MonadFail m) => a -> m D10+integralD10Fail x = integerD10Fail (toInteger x)
+ src/D10/Char/Quotes.hs view
@@ -0,0 +1,104 @@+{-# language Safe #-}++module D10.Char.Quotes where++import D10.Char.Conversions+import D10.Char.Splices++import Control.Monad ((>=>))+import Control.Monad.Fail (MonadFail (fail))+import Language.Haskell.TH.Quote (QuasiQuoter (..))+import Prelude hiding (fail)++-- | A single base-10 digit.+--+-- This quasi-quoter, when used as an expression, produces a+-- value of type 'D10'.+--+-- >>> d10Nat [d10|5|]+-- 5+--+-- >>> d10Nat [d10|a|]+-- ...+-- ... d10 must be between 0 and 9+-- ...+--+-- >>> d10Nat [d10|58|]+-- ...+-- ... d10 must be a single character+-- ...+--+-- This quasi-quoter can also be used as a pattern.+--+-- >>> :{+--       case (charD10Maybe '5') of+--         Just [d10|4|] -> "A"+--         Just [d10|5|] -> "B"+--         _             -> "C"+-- >>> :}+-- "B"+--+-- >>> :{+--       case (charD10Maybe '5') of+--         Just [d10|x|] -> "A"+--         Just [d10|5|] -> "B"+--         _             -> "C"+-- >>> :}+-- ...+-- ... d10 must be between 0 and 9+-- ...++d10 :: QuasiQuoter+d10 = QuasiQuoter+    { quoteExp  = strD10Fail >=> (d10Exp . d10Integer)+    , quotePat  = strD10Fail >=> (d10Pat . d10Integer)+    , quoteType = \_ -> fail "d10 cannot be used in a type context"+    , quoteDec  = \_ -> fail "d10 cannot be used in a declaration context"+    }++-- | A list of base-10 digits.+--+-- This quasi-quoter, when used as an expression, produces a+-- value of type @['D10']@.+--+-- >>> d10Nat <$> [d10list||]+-- []+--+-- >>> d10Nat <$> [d10list|5|]+-- [5]+--+-- >>> d10Nat <$> [d10list|58|]+-- [5,8]+--+-- >>> d10Nat <$> [d10list|a|]+-- ...+-- ... d10 must be between 0 and 9+-- ...+--+-- This quasi-quoter can also be used as a pattern.+--+-- >>> :{+--       case [d10list|56|] of+--         [d10list|41|] -> "A"+--         [d10list|56|] -> "B"+--         _             -> "C"+-- >>> :}+-- "B"+--+-- >>> :{+--       case [d10list|56|] of+--         [d10list|4x|] -> "A"+--         [d10list|56|] -> "B"+--         _             -> "C"+-- >>> :}+-- ...+-- ... d10 must be between 0 and 9+-- ...++d10list :: QuasiQuoter+d10list = QuasiQuoter+    { quoteExp  = d10ListExp+    , quotePat  = d10ListPat+    , quoteType = \_ -> fail "d10list cannot be used in a type context"+    , quoteDec  = \_ -> fail "d10list cannot be used in a declaration context"+    }
+ src/D10/Char/Splices.hs view
@@ -0,0 +1,102 @@+{-# language Trustworthy, TemplateHaskell #-}++module D10.Char.Splices+    (+    -- * Expressions+      d10Exp, d10ListExp+    -- * Patterns+    , d10Pat, d10ListPat+    ) where++import D10.Char.Conversions+import D10.Char.Unsafe++import Control.Monad ((>=>))+import Language.Haskell.TH.Lib (appE, charL, conE, litE, litP)+import Language.Haskell.TH.Syntax (Exp (..), Pat (..), Q)++-- | Produces an expression of type 'D10' that can be used+-- in a Template Haskell splice.+--+-- >>> d10Nat $(d10Exp 5)+-- 5+--+-- >>> d10Nat $(d10Exp 12)+-- ...+-- ... d10 must be between 0 and 9+-- ...+--+-- You may also be interested in 'd10', a quasi-quoter which+-- does something similar.++d10Exp :: Integer -> Q Exp+d10Exp = integerD10Fail >=> d10Exp'++d10Exp' :: D10 -> Q Exp+d10Exp' x = conE 'D10_Unsafe `appE` litE (charL (d10Char x))++-- | Produces an expression of type @['D10']@ that can be used+-- in a Template Haskell splice.+--+-- >>> d10Nat <$> $(d10ListExp "")+-- []+--+-- >>> d10Nat <$> $(d10ListExp "5")+-- [5]+--+-- >>> d10Nat <$> $(d10ListExp "58")+-- [5,8]+--+-- >>> d10Nat <$> $(d10ListExp "a")+-- ...+-- ... d10 must be between 0 and 9+-- ...+--+-- You may also be interested in 'd10list', a quasi-quoter which+-- does something similar.++d10ListExp :: String -> Q Exp+d10ListExp = strD10ListFail >=> d10ListExp'++d10ListExp' :: [D10] -> Q Exp+d10ListExp' =+  foldr+    (\x e -> conE '(:) `appE` d10Exp' x `appE` e)+    (conE '[])++---------------------------------------------------++-- | Produces a pattern that can be used in a splice+-- to match a particular 'D10' value.+--+-- >>> :{+--       case (charD10Maybe '5') of+--         Just $(d10Pat 4) -> "A"+--         Just $(d10Pat 5) -> "B"+--         _                -> "C"+-- >>> :}+-- "B"+--+-- You may wish to use the 'd10' quasi-quoter instead.++d10Pat :: Integer -> Q Pat+d10Pat = integerD10Fail >=> d10Pat'++d10Pat' :: D10 -> Q Pat+d10Pat' (D10_Unsafe x) = [p| D10_Unsafe $(litP $ charL x) |]++-- | Produces a pattern that can be used in a splice+-- to match a particular list of 'D10' values.+--+-- >>> :{+--       case (strD10ListMaybe "56") of+--         Just $(d10ListPat "42") -> "A"+--         Just $(d10ListPat "56") -> "B"+--         _                       -> "C"+-- >>> :}+-- "B"+--+-- You may wish to use the 'd10list' quasi-quoter instead.++d10ListPat :: String -> Q Pat+d10ListPat = strD10ListFail >=> foldr (\x p -> [p| $(d10Pat' x) : $(p) |]) [p| [] |]
+ src/D10/Char/Type.hs view
@@ -0,0 +1,5 @@+{-# language Trustworthy #-}++module D10.Char.Type (D10) where++import D10.Char.Unsafe
+ src/D10/Char/Unsafe.hs view
@@ -0,0 +1,65 @@+{-# language Unsafe, GeneralizedNewtypeDeriving #-}++module D10.Char.Unsafe (D10 (D10_Unsafe)) where++import qualified D10.Predicate as Predicate++import Data.Char (chr, ord)+import Data.Monoid (Endo (..))++---------------------------------------------------++-- | A 'Char' value between @'0'@ and @'9'@+newtype D10 =+    D10_Unsafe Char+      -- ^ 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 (Eq, Ord)++---------------------------------------------------++instance Bounded D10+  where+    minBound = D10_Unsafe '0'+    maxBound = D10_Unsafe '9'++---------------------------------------------------++instance Enum D10+  where+    fromEnum :: D10 -> Int+    fromEnum (D10_Unsafe x) = ord x - ord '0'++    toEnum :: Int -> D10+    toEnum x | Predicate.isD10Int x = D10_Unsafe (chr (x + ord '0'))+             | otherwise = error "d10 must be between 0 and 9"++    enumFrom :: D10 -> [D10]+    enumFrom x = enumFromTo x maxBound++    enumFromThen :: D10 -> D10 -> [D10]+    enumFromThen x y = enumFromThenTo x y bound+      where+        bound | fromEnum y >= fromEnum x = maxBound+              | otherwise                = minBound++    succ :: D10 -> D10+    succ (D10_Unsafe '9') = error "D10 overflow"+    succ (D10_Unsafe x) = D10_Unsafe (succ x)++    pred :: D10 -> D10+    pred (D10_Unsafe '0') = error "D10 underflow"+    pred (D10_Unsafe x) = D10_Unsafe (pred x)++---------------------------------------------------++instance Show D10 where+    showsPrec _ x = showString "[d10|"     . showsChar x . showString "|]"+    showList xs   = showString "[d10list|" . showsStr xs . showString "|]"++showsChar :: D10 -> ShowS+showsChar (D10_Unsafe x) = showChar x++showsStr :: [D10] -> ShowS+showsStr = appEndo . foldMap (Endo . showsChar)
+ src/D10/Num.hs view
@@ -0,0 +1,138 @@+{-# language Safe #-}++{- |++Defines a 'D10' type as a newtype for any type with an+instance of the 'Num' class, where the values are restricted+to numbers between @'fromInteger' 0@ and @'fromInteger' 9@.++This module provides many functions for constructing 'D10'+values, including:++  * @'integerD10Maybe' :: 'Num' a => 'Integer' -> 'Maybe' ('D10' a)@+  * @'integerMod10' :: 'Num' a => 'Integer' -> 'D10' a@++There are also several ways to safely write 'D10' literals+using Template Haskell:++  * With the @QuasiQuotes@ GHC extension enabled, you can write+    use the quasi-quoters 'd10' and 'd10list'.+  * With the @TemplateHaskell@ GHC extension enabled, you can+    splice expressions produced by 'd10Exp' and 'd10ListExp'.++-}++module D10.Num+    (+    -- * Related modules+    -- $modules++    -- * Type+      D10++    -- ** Bounded+    -- $bounded++    -- ** Enum+    -- $enum++    -- ** Show+    -- $show++    -- * Quasi-quoters+    , d10, d10list++    -- * Splices+    -- ** Expressions+    , d10Exp, d10ListExp+    -- ** Patterns+    , d10Pat, d10ListPat++    -- * Conversions+    -- ** D10 / Char+    , d10Char, charD10Maybe, charD10Either, charD10Fail+    -- ** D10 / String+    , d10Str, strD10Maybe, strD10Either, strD10Fail+    -- ** [D10] / String+    , strD10ListMaybe, strD10ListEither, strD10ListFail+    -- ** D10 / Natural+    , d10Nat, natD10Maybe, natD10Either, natD10Fail+    , natMod10+    -- ** D10 / Integer+    , d10Integer, integerD10Maybe, integerD10Either+    , integerD10Fail, integerMod10+    -- ** D10 / Int+    , d10Int, intD10Maybe, intD10Either, intD10Fail+    , intMod10+    -- ** D10 / general numeric types+    , d10Num, integralD10Maybe, integralD10Either+    , integralD10Fail, integralMod10++    ) where++import D10.Num.Conversions+import D10.Num.Type+import D10.Num.Quotes+import D10.Num.Splices++{- $modules++Additional functions related to this 'D10' type may be found in:++  * "D10.Num.Arithmetic"++The contents of the following modules are re-exported here:++  * "D10.Num.Conversions"+  * "D10.Num.Quotes"+  * "D10.Num.Splices"+  * "D10.Num.Type"++The unsafe constructor for 'D10' can be found in:++  * "D10.Num.Unsafe"++The following modules define @D10@ types in different ways+but are otherwise very similar to this one:++  * "D10.Char"+  * "D10.Safe"++-}++{- $bounded++>>> minBound :: D10 Integer+[d10|0|]++>>> maxBound :: D10 Integer+[d10|9|]++-}++{- $enum++>>> [ [d10|5|] .. ]+[d10list|56789|]++>>> [ [d10|4|] .. [d10|7|] ]+[d10list|4567|]++>>> [ [d10|5|], [d10|4|] .. ]+[d10list|543210|]++>>> [ [d10|1|], [d10|3|] .. ]+[d10list|13579|]++>>> [ minBound .. maxBound ] :: [D10 Integer]+[d10list|0123456789|]++-}++{- $show++'show' shows base-10 digits using the quasiquoters defined+in this module. A single digit is displayed using 'd10'.+A list of digits is displayed using 'd10list'.++-}
+ src/D10/Num/Arithmetic.hs view
@@ -0,0 +1,41 @@+{-# language Safe #-}++module D10.Num.Arithmetic where++import D10.Num (D10, d10Int, intMod10)++import qualified Prelude as P+import Prelude (Integral)++-- | Addition modulo 10.+--+-- >>> [d10|2|] + [d10|3|]+-- [d10|5|]+--+-- >>> [d10|6|] + [d10|7|]+-- [d10|3|]++(+) :: Integral a => D10 a -> D10 a -> D10 a+x + y = intMod10 (d10Int x P.+ d10Int y)++-- | Subtraction modulo 10.+--+-- >>> [d10|7|] - [d10|5|]+-- [d10|2|]+--+-- >>> [d10|3|] - [d10|7|]+-- [d10|6|]++(-) :: Integral a => D10 a -> D10 a -> D10 a+x - y = intMod10 (d10Int x P.- d10Int y)++-- | Multiplication modulo 10.+--+-- >>> [d10|2|] * [d10|4|]+-- [d10|8|]+--+-- >>> [d10|7|] * [d10|8|]+-- [d10|6|]++(*) :: Integral a => D10 a -> D10 a -> D10 a+x * y = intMod10 (d10Int x P.* d10Int y)
+ src/D10/Num/Conversions.hs view
@@ -0,0 +1,547 @@+{-# language Trustworthy #-}++module D10.Num.Conversions+    (+    -- * D10 / Char+      d10Char, charD10Maybe, charD10Either, charD10Fail+    -- * D10 / String+    , d10Str, strD10Maybe, strD10Either, strD10Fail+    -- * [D10] / String+    , strD10ListMaybe, strD10ListEither, strD10ListFail+    -- * D10 / Natural+    , d10Nat, natD10Maybe, natD10Either, natD10Fail+    , natMod10+    -- * D10 / Integer+    , d10Integer, integerD10Maybe, integerD10Either+    , integerD10Fail, integerMod10+    -- * D10 / Int+    , d10Int, intD10Maybe, intD10Either, intD10Fail+    , intMod10+    -- * D10 / general numeric types+    , d10Num, integralD10Maybe, integralD10Either+    , integralD10Fail, integralMod10+    ) where++import D10.Num.Unsafe (D10(..))+import D10.Predicate (isD10Char, isD10Int, isD10Integer, isD10Nat)++-- base+import Control.Monad.Fail (MonadFail (fail))+import Data.Char          (chr, ord)+import Numeric.Natural    (Natural)+import Prelude            hiding (fail)++import qualified Prelude as P++-- | Convert a 'D10' to its underlying 'Char' representation.+--+-- >>> d10Char [d10|7|]+-- '7'++d10Char :: Integral a => D10 a -> Char+d10Char (D10_Unsafe x) = chr (ord '0' P.+ fromIntegral x)++-- | Convert a 'D10' to a 'String'.+--+-- @'d10Str' x = ['d10Char' x]@+--+-- >>> d10Str [d10|7|]+-- "7"++d10Str :: Integral a => D10 a -> String+d10Str x = [d10Char x]++-- | Convert a 'D10' to a 'Natural'.+--+-- 'd10Num' is a more general version of this function.+--+-- >>> d10Nat [d10|7|]+-- 7++d10Nat :: Integral a => D10 a -> Natural+d10Nat = d10Num++-- | Convert a 'D10' to an 'Integer'.+--+-- 'd10Num' is a more general version of this function.+--+-- >>> d10Integer [d10|7|]+-- 7++d10Integer :: Integral a => D10 a -> Integer+d10Integer = d10Num++-- | Convert a 'D10' to an 'Int'.+--+-- 'd10Num' is a more general version of this function.+--+-- >>> d10Int [d10|7|]+-- 7++d10Int :: Integral a => D10 a -> Int+d10Int = d10Num++-- | Convert a 'D10' to any kind of number with a 'Num' instance.+--+-- Specialized versions of this function include 'd10Nat',+-- 'd10Integer', and 'd10Int'.+--+-- >>> d10Num [d10|7|] :: Integer+-- 7++d10Num :: (Integral b, Num a) => D10 b -> a+d10Num (D10_Unsafe x) = fromIntegral x++---------------------------------------------------++-- | The 'D10' which is uniquely congruent modulo 10 to the given 'Natural'.+--+-- 'integralMod10' is a more general version of this function.+--+-- >>> natMod10 56 :: D10 Int+-- [d10|6|]++natMod10 :: Num a => Natural -> D10 a+natMod10 = integralMod10++-- | The 'D10' which is uniquely congruent modulo 10 to the given 'Integer'.+--+-- 'integralMod10' is a more general version of this function.+--+-- >>> integerMod10 56 :: D10 Int+-- [d10|6|]+--+-- >>> integerMod10 (-56) :: D10 Int+-- [d10|4|]++integerMod10 :: Num a => Integer -> D10 a+integerMod10 = integralMod10++-- | The 'D10' which is uniquely congruent modulo 10 to the given 'Int'.+--+-- 'integralMod10' is a more general version of this function.+--+-- >>> intMod10 56 :: D10 Int+-- [d10|6|]+--+-- >>> intMod10 (-56) :: D10 Int+-- [d10|4|]++intMod10 :: Num a => Int -> D10 a+intMod10 = integralMod10++-- | The 'D10' which is uniquely congruent modulo 10 to the given number+-- (whose type must have an instance of the 'Integral' class).+--+-- Specialized versions of this function include 'natMod10',+-- 'integerMod10', and 'intMod10'.+--+-- >>> integralMod10 (56 :: Integer) :: D10 Int+-- [d10|6|]+--+-- >>> integralMod10 ((-56) :: Integer) :: D10 Int+-- [d10|4|]++integralMod10 :: (Num b, Integral a) => a -> D10 b+integralMod10 x = D10_Unsafe (fromIntegral (x `mod` 10))++---------------------------------------------------++-- | Convert a 'Char' to a 'D10' if it is within the range+-- @'0'@ to @'9'@, or produce 'Nothing' otherwise.+--+-- @'D10.Predicate.isD10Char' x = 'Data.Maybe.isJust' ('charD10Maybe' x)@+--+-- 'charD10Fail' is a more general version of this function.+--+-- >>> charD10Maybe '5'+-- Just [d10|5|]+--+-- >>> charD10Maybe 'a'+-- Nothing++charD10Maybe :: Num a => Char -> Maybe (D10 a)+charD10Maybe x+        | isD10Char x  =  Just (D10_Unsafe (fromIntegral (ord x P.- ord '0')))+        | otherwise    =  Nothing++-- | Convert a 'String' to a 'D10' if it consists of exactly one+-- character and that character is within the range @'0'@ to @'9'@,+-- or produce 'Nothing' otherwise.+--+-- @'D10.Predicate.isD10Str' x = 'Data.Maybe.isJust' ('strD10Maybe' x)@+--+-- 'strD10Fail' is a more general version of this function.+--+-- >>> strD10Maybe "5"+-- Just [d10|5|]+--+-- >>> strD10Maybe "a"+-- Nothing+--+-- >>> strD10Maybe "58"+-- Nothing++strD10Maybe :: Num a => String -> Maybe (D10 a)+strD10Maybe [x] = charD10Maybe x+strD10Maybe _   = Nothing++-- | Convert a 'String' to a list of 'D10' if all of the characters+-- in the string are within the range @'0'@ to @'9'@, or produce+-- 'Nothing' otherwise.+--+-- @'D10.Predicate.isD10ListStr' x = 'Data.Maybe.isJust' ('strD10ListMaybe' x)@+--+-- 'strD10ListFail' is a more general version of this function.+--+-- >>> strD10ListMaybe "5"+-- Just [d10list|5|]+--+-- >>> strD10ListMaybe "a"+-- Nothing+--+-- >>> strD10ListMaybe "58"+-- Just [d10list|58|]++strD10ListMaybe :: Num a => String -> Maybe [D10 a]+strD10ListMaybe = traverse charD10Maybe++-- | Convert a 'Natural' to a 'D10' if it is less than 10,+-- or produce 'Nothing' otherwise.+--+-- @'D10.Predicate.isD10Nat' x = 'Data.Maybe.isJust' ('natD10Maybe' x)@+--+-- 'integralD10Maybe', 'natD10Fail', and 'integralD10Fail'+-- are more general versions of this function.+--+-- >>> natD10Maybe 5+-- Just [d10|5|]+--+-- >>> natD10Maybe 12+-- Nothing++natD10Maybe :: Num a => Natural -> Maybe (D10 a)+natD10Maybe x+        | isD10Nat x  =  Just (D10_Unsafe (fromIntegral x))+        | otherwise   =  Nothing++-- | Convert an 'Integer' to a 'D10' if it is within the range 0 to 9,+-- or produce 'Nothing' otherwise.+--+-- @'D10.Predicate.isD10Integer' x = 'Data.Maybe.isJust' ('integerD10Maybe' x)@+--+-- 'integralD10Maybe', 'integerD10Fail', and 'integralD10Fail'+-- are more general versions of this function.+--+-- >>> integerD10Maybe 5+-- Just [d10|5|]+--+-- >>> integerD10Maybe 12+-- Nothing+--+-- >>> integerD10Maybe (-5)+-- Nothing++integerD10Maybe :: Num a => Integer -> Maybe (D10 a)+integerD10Maybe x+        | isD10Integer x  =  Just (D10_Unsafe (fromIntegral x))+        | otherwise       =  Nothing++-- | Convert an 'Int' to a 'D10' if it is within the range 0 to 9,+-- or produce 'Nothing' otherwise.+--+-- @'D10.Predicate.isD10Int' x = 'Data.Maybe.isJust' ('intD10Maybe' x)@+--+-- 'integralD10Maybe', 'intD10Fail', and 'integralD10Fail'+-- are more general versions of this function.+--+-- >>> intD10Maybe 5+-- Just [d10|5|]+--+-- >>> intD10Maybe 12+-- Nothing+--+-- >>> intD10Maybe (-5)+-- Nothing++intD10Maybe :: Num a => Int -> Maybe (D10 a)+intD10Maybe x+        | isD10Int x  =  Just (D10_Unsafe (fromIntegral x))+        | otherwise   =  Nothing++-- | Construct a 'D10' from any kind of number with an 'Integral'+-- instance, or produce 'Nothing' if the number falls outside the+-- range 0 to 9.+--+-- @'D10.Predicate.isD10Integral' x = 'Data.Maybe.isJust' ('integralD10Maybe' x)@+--+-- Specialized versions of this function include 'natD10Maybe',+-- 'integerD10Maybe', and 'intD10Maybe'.+--+-- 'integralD10Fail' is a more general version of this function.+--+-- >>> integralD10Maybe (5 :: Integer)+-- Just [d10|5|]+--+-- >>> integralD10Maybe (12 :: Integer)+-- Nothing+--+-- >>> integralD10Maybe ((-5) :: Integer)+-- Nothing++integralD10Maybe :: (Num b, Integral a) => a -> Maybe (D10 b)+integralD10Maybe x = integerD10Maybe (toInteger x)++---------------------------------------------------++-- | Convert a 'Char' to a 'D10' if it is within the range+-- @'0'@ to @'9'@, or 'Left' with an error message otherwise.+--+-- >>> charD10Either '5'+-- Right [d10|5|]+--+-- >>> charD10Either 'a'+-- Left "d10 must be between 0 and 9"++charD10Either :: Num a => Char -> Either String (D10 a)+charD10Either x+        | isD10Char x  =  Right (D10_Unsafe (fromIntegral (ord x P.- ord '0')))+        | otherwise    =  Left "d10 must be between 0 and 9"++-- | Convert a 'String' to a 'D10' if it consists of a single+-- character and that character is within the range @'0'@ to+-- @'9'@, or 'Left' with an error message otherwise.+--+-- >>> strD10Either "5"+-- Right [d10|5|]+--+-- >>> strD10Either "a"+-- Left "d10 must be between 0 and 9"+--+-- >>> strD10Either "58"+-- Left "d10 must be a single character"++strD10Either :: Num a => String -> Either String (D10 a)+strD10Either [x]         =  charD10Either x+strD10Either _           =  Left "d10 must be a single character"++-- | Convert a 'String' to a 'D10' if all of the characters in+-- the string fall within the range @'0'@ to @'9'@, or 'Left'+-- with an error message otherwise.+--+-- >>> strD10ListEither "5"+-- Right [d10list|5|]+--+-- >>> strD10ListEither "a"+-- Left "d10 must be between 0 and 9"+--+-- >>> strD10ListEither "58"+-- Right [d10list|58|]++strD10ListEither :: Num a => String -> Either String [D10 a]+strD10ListEither = traverse charD10Either++-- | Convert a 'Natural' to a 'D10' if it is less than 10,+-- or 'Left' with an error message otherwise.+--+-- >>> natD10Either 5+-- Right [d10|5|]+--+-- >>> natD10Either 12+-- Left "d10 must be less than 10"++natD10Either :: Num a => Natural -> Either String (D10 a)+natD10Either x =+    case (natD10Maybe x) of+        Just y  -> Right y+        Nothing -> Left "d10 must be less than 10"++-- | Convert an 'Integer' to a 'D10' if it is within the+-- range 0 to 9, or 'Left' with an error message otherwise.+--+-- >>> integerD10Either 5+-- Right [d10|5|]+--+-- >>> integerD10Either 12+-- Left "d10 must be between 0 and 9"+--+-- >>> integerD10Either (-5)+-- Left "d10 must be between 0 and 9"++integerD10Either :: Num a => Integer -> Either String (D10 a)+integerD10Either x =+    case (integerD10Maybe x) of+        Just y  -> Right y+        Nothing -> Left "d10 must be between 0 and 9"++-- | Convert an 'Int' to a 'D10' if it is within the range+-- 0 to 9, or 'Left' with an error message otherwise.+--+-- >>> intD10Either 5+-- Right [d10|5|]+--+-- >>> intD10Either 12+-- Left "d10 must be between 0 and 9"+--+-- >>> intD10Either (-5)+-- Left "d10 must be between 0 and 9"++intD10Either :: Num a => Int -> Either String (D10 a)+intD10Either x =+    case (intD10Maybe x) of+        Just y  ->  Right y+        Nothing ->  Left "d10 must be between 0 and 9"++-- | Convert a number of a type that has an 'Integral' instance+-- to a 'D10' if it falls within the range 0 to 9, or 'Left'+-- with an error message otherwise.+--+-- >>> integralD10Either (5 :: Integer)+-- Right [d10|5|]+--+-- >>> integralD10Either (12 :: Integer)+-- Left "d10 must be between 0 and 9"+--+-- >>> integralD10Either ((-5) :: Integer)+-- Left "d10 must be between 0 and 9"++integralD10Either :: (Num b, Integral a) => a -> Either String (D10 b)+integralD10Either x = integerD10Either (toInteger x)++---------------------------------------------------++-- | Convert a 'Char' to a 'D10' if it is within the range+-- @'0'@ to @'9'@, or 'fail' with an error message otherwise.+--+-- 'charD10Maybe' is a specialized version of this function.+--+-- >>> charD10Fail '5' :: IO (D10 Int)+-- [d10|5|]+--+-- >>> charD10Fail 'a' :: IO (D10 Int)+-- *** Exception: user error (d10 must be between 0 and 9)++charD10Fail :: (Num a, MonadFail m) => Char -> m (D10 a)+charD10Fail x+        | isD10Char x  =  return (D10_Unsafe (fromIntegral (ord x P.- ord '0')))+        | otherwise    =  fail "d10 must be between 0 and 9"++-- | Convert a 'String' to a 'D10' if it consists of a single+-- character and that character is within the range @'0'@ to+-- @'9'@, or 'fail' with an error message otherwise.+--+-- 'strD10Maybe' is a specialized version of this function.+--+-- >>> strD10Fail "5" :: IO (D10 Int)+-- [d10|5|]+--+-- >>> strD10Fail "a" :: IO (D10 Int)+-- *** Exception: user error (d10 must be between 0 and 9)+--+-- >>> strD10Fail "58" :: IO (D10 Int)+-- *** Exception: user error (d10 must be a single character)++strD10Fail :: (Num a, MonadFail m) => String -> m (D10 a)+strD10Fail [x]         =  charD10Fail x+strD10Fail _           =  fail "d10 must be a single character"++-- | Convert a 'String' to a 'D10' if all of the characters in+-- the string fall within the range @'0'@ to @'9'@, or 'fail'+-- with an error message otherwise.+--+-- 'strD10ListMaybe' is a specialized version of this function.+--+-- >>> strD10ListFail "5" :: IO [D10 Int]+-- [d10list|5|]+--+-- >>> strD10ListFail "a" :: IO [D10 Int]+-- *** Exception: user error (d10 must be between 0 and 9)+--+-- >>> strD10ListFail "58" :: IO [D10 Int]+-- [d10list|58|]++strD10ListFail :: (Num a, MonadFail m) => String -> m [D10 a]+strD10ListFail = traverse charD10Fail++-- | Convert a 'Natural' to a 'D10' if it is less than 10,+-- or 'fail' with an error message otherwise.+--+-- 'natD10Maybe' is a specialized version of this function.+--+-- 'integralD10Fail' is a more general version of this function.+--+-- >>> natD10Fail 5 :: IO (D10 Int)+-- [d10|5|]+--+-- >>> natD10Fail 12 :: IO (D10 Int)+-- *** Exception: user error (d10 must be less than 10)++natD10Fail :: (Num a, MonadFail m) => Natural -> m (D10 a)+natD10Fail x =+    case (natD10Maybe x) of+        Just y  -> return y+        Nothing -> fail "d10 must be less than 10"++-- | Convert an 'Integer' to a 'D10' if it is within the+-- range 0 to 9, or 'fail' with an error message otherwise.+--+-- 'integerD10Maybe' is a specialized version of this function.+--+-- 'integralD10Fail' is a more general version of this function.+--+-- >>> integerD10Fail 5 :: IO (D10 Int)+-- [d10|5|]+--+-- >>> integerD10Fail 12 :: IO (D10 Int)+-- *** Exception: user error (d10 must be between 0 and 9)+--+-- >>> integerD10Fail (-5) :: IO (D10 Int)+-- *** Exception: user error (d10 must be between 0 and 9)++integerD10Fail :: (Num a, MonadFail m) => Integer -> m (D10 a)+integerD10Fail x =+    case (integerD10Maybe x) of+        Just y  -> return y+        Nothing -> fail "d10 must be between 0 and 9"++-- | Convert an 'Int' to a 'D10' if it is within the range+-- 0 to 9, or 'fail' with an error message otherwise.+--+-- 'intD10Maybe' is a specialized version of this function.+--+-- 'integralD10Fail' is a more general version of this function.+--+-- >>> intD10Fail 5 :: IO (D10 Int)+-- [d10|5|]+--+-- >>> intD10Fail 12 :: IO (D10 Int)+-- *** Exception: user error (d10 must be between 0 and 9)+--+-- >>> intD10Fail (-5) :: IO (D10 Int)+-- *** Exception: user error (d10 must be between 0 and 9)++intD10Fail :: (Num a, MonadFail m) => Int -> m (D10 a)+intD10Fail x =+    case (intD10Maybe x) of+        Just y  ->  return y+        Nothing ->  fail "d10 must be between 0 and 9"++-- | Convert a number of a type that has an 'Integral' instance+-- to a 'D10' if it falls within the range 0 to 9, or 'fail'+-- with an error message otherwise.+--+-- 'natD10Maybe', 'integerD10Maybe', 'intD10Maybe',+-- 'integralD10Maybe', 'natD10Fail', 'integerD10Fail', and+-- 'intD10Fail' are all specialized versions of this function.+--+-- >>> integralD10Fail (5 :: Integer) :: IO (D10 Int)+-- [d10|5|]+--+-- >>> integralD10Fail (12 :: Integer) :: IO (D10 Int)+-- *** Exception: user error (d10 must be between 0 and 9)+--+-- >>> integralD10Fail ((-5) :: Integer) :: IO (D10 Int)+-- *** Exception: user error (d10 must be between 0 and 9)++integralD10Fail :: (Num b, Integral a, MonadFail m) => a -> m (D10 b)+integralD10Fail x = integerD10Fail (toInteger x)
+ src/D10/Num/Quotes.hs view
@@ -0,0 +1,104 @@+{-# language Safe #-}++module D10.Num.Quotes where++import D10.Num.Conversions+import D10.Num.Splices++import Control.Monad ((>=>))+import Control.Monad.Fail (MonadFail (fail))+import Prelude hiding (fail)+import Language.Haskell.TH.Quote (QuasiQuoter (..))++-- | A single base-10 digit.+--+-- This quasi-quoter, when used as an expression, produces a+-- value of type @'D10' a@.+--+-- >>> d10Nat [d10|5|]+-- 5+--+-- >>> d10Nat [d10|a|]+-- ...+-- ... d10 must be between 0 and 9+-- ...+--+-- >>> d10Nat [d10|58|]+-- ...+-- ... d10 must be a single character+-- ...+--+-- This quasi-quoter can also be used as a pattern.+--+-- >>> :{+--       case (charD10Maybe '5') of+--         Just [d10|4|] -> "A"+--         Just [d10|5|] -> "B"+--         _             -> "C"+-- >>> :}+-- "B"+--+-- >>> :{+--       case (charD10Maybe '5') of+--         Just [d10|x|] -> "A"+--         Just [d10|5|] -> "B"+--         _             -> "C"+-- >>> :}+-- ...+-- ... d10 must be between 0 and 9+-- ...++d10 :: QuasiQuoter+d10 = QuasiQuoter+    { quoteExp  = strD10Fail >=> (d10Exp . d10Integer @Integer)+    , quotePat  = strD10Fail >=> (d10Pat . d10Integer @Integer)+    , quoteType = \_ -> fail "d10 cannot be used in a type context"+    , quoteDec  = \_ -> fail "d10 cannot be used in a declaration context"+    }++-- | A list of base-10 digits.+--+-- This quasi-quoter, when used as an expression, produces a+-- value of type @['D10' a]@.+--+-- >>> d10Nat <$> [d10list||]+-- []+--+-- >>> d10Nat <$> [d10list|5|]+-- [5]+--+-- >>> d10Nat <$> [d10list|58|]+-- [5,8]+--+-- >>> d10Nat <$> [d10list|a|]+-- ...+-- ... d10 must be between 0 and 9+-- ...+--+-- This quasi-quoter can also be used as a pattern.+--+-- >>> :{+--       case [d10list|56|] of+--         [d10list|41|] -> "A"+--         [d10list|56|] -> "B"+--         _             -> "C"+-- >>> :}+-- "B"+--+-- >>> :{+--       case [d10list|56|] of+--         [d10list|4x|] -> "A"+--         [d10list|56|] -> "B"+--         _             -> "C"+-- >>> :}+-- ...+-- ... d10 must be between 0 and 9+-- ...++d10list :: QuasiQuoter+d10list = QuasiQuoter+    { quoteExp  = d10ListExp+    , quotePat  = d10ListPat+    , quoteType = \_ -> fail "d10list cannot be used in a type context"+    , quoteDec  = \_ -> fail "d10list cannot be used in a declaration context"+    }
+ src/D10/Num/Splices.hs view
@@ -0,0 +1,108 @@+{-# language Trustworthy, TemplateHaskell #-}++module D10.Num.Splices+    (+    -- * Expressions+      d10Exp, d10ListExp+    -- * Patterns+    , d10Pat, d10ListPat+    ) where++import D10.Num.Conversions+import D10.Num.Unsafe (D10(..))++import Control.Monad ((>=>))+import Language.Haskell.TH.Lib (appE, conE, integerL, litE, litP, varE)+import Language.Haskell.TH.Syntax (Exp (..), Pat (..), Q)++-- | Produces an expression of type @'D10' a@ that can be used+-- in a Template Haskell splice.+--+-- >>> d10Nat $(d10Exp 5)+-- 5+--+-- >>> d10Nat $(d10Exp 12)+-- ...+-- ... d10 must be between 0 and 9+-- ...+--+-- You may also be interested in 'd10', a quasi-quoter which+-- does something similar.++d10Exp :: Integer -> Q Exp+d10Exp = integerD10Fail >=> d10Exp'++d10Exp' :: D10 Integer -> Q Exp+d10Exp' (D10_Unsafe x) = conE 'D10_Unsafe `appE` (varE 'fromInteger `appE` litE (integerL x))++-- | Produces an expression of type @['D10' a]@ that can be used+-- in a Template Haskell splice.+--+-- >>> d10Nat <$> $(d10ListExp "")+-- []+--+-- >>> d10Nat <$> $(d10ListExp "5")+-- [5]+--+-- >>> d10Nat <$> $(d10ListExp "58")+-- [5,8]+--+-- >>> d10Nat <$> $(d10ListExp "a")+-- ...+-- ... d10 must be between 0 and 9+-- ...+--+-- You may also be interested in 'd10list', a quasi-quoter which+-- does something similar.++d10ListExp :: String -> Q Exp+d10ListExp = strD10ListFail >=> d10ListExp'++d10ListExp' :: [D10 Integer] -> Q Exp+d10ListExp' =+  foldr+    (\x e -> conE '(:) `appE` d10Exp' x `appE` e)+    (conE '[])++---------------------------------------------------++-- | Produces a pattern that can be used in a splice+-- to match a particular @'D10' a@ value.+--+-- >>> :{+--       case (charD10Maybe '5') of+--         Just $(d10Pat 4) -> "A"+--         Just $(d10Pat 5) -> "B"+--         _                -> "C"+-- >>> :}+-- "B"+--+-- You may wish to use the 'd10' quasi-quoter instead.++d10Pat :: Integer -> Q Pat+d10Pat = integerD10Fail >=> d10Pat'++d10Pat' :: D10 Integer -> Q Pat+d10Pat' (D10_Unsafe x) = [p| D10_Unsafe $(litP $ integerL x) |]++d10Pat'' :: Integral a => D10 a -> Q Pat+d10Pat'' (D10_Unsafe x) = [p| D10_Unsafe $(litP $ integerL $ toInteger x) |]++-- | Produces a pattern that can be used in a splice+-- to match a particular list of @'D10' a@ values.+--+-- >>> :{+--       case (strD10ListMaybe "56") of+--         Just $(d10ListPat "42") -> "A"+--         Just $(d10ListPat "56") -> "B"+--         _                       -> "C"+-- >>> :}+-- "B"+--+-- You may wish to use the 'd10list' quasi-quoter instead.++d10ListPat :: String -> Q Pat+d10ListPat = strD10ListFail >=> d10ListPat'++d10ListPat' :: [D10 Integer] -> Q Pat+d10ListPat' = foldr (\x p -> [p| $(d10Pat'' x) : $(p) |]) [p| [] |]
+ src/D10/Num/Type.hs view
@@ -0,0 +1,5 @@+{-# language Trustworthy #-}++module D10.Num.Type (D10) where++import D10.Num.Unsafe
+ src/D10/Num/Unsafe.hs view
@@ -0,0 +1,64 @@+{-# language Unsafe, GeneralizedNewtypeDeriving #-}++module D10.Num.Unsafe (D10 (..)) where++import qualified D10.Predicate as Predicate++import Data.Char (chr, ord)+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 (Eq, Ord)++---------------------------------------------------++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)
+ src/D10/Predicate.hs view
@@ -0,0 +1,39 @@+{-# language Safe #-}++-- | Functions to test whether values of various+-- types represent digits in the range /0/ to /9/.+module D10.Predicate where++import Numeric.Natural (Natural)++-- | Determines whether a 'Char' is in the range @'0'@ to @'9'@.+isD10Char :: Char -> Bool+isD10Char x = x >= '0' && x <= '9'++-- | Determines whether a 'String' consists of a single character+-- and that character is within the range @'0'@ to @'9'@.+isD10Str :: String -> Bool+isD10Str [x] = isD10Char x+isD10Str _   = False++-- | Determines whether a 'String' consists entirely of characters+-- that are within the range @'0'@ to @'9'@.+isD10ListStr :: String -> Bool+isD10ListStr = all isD10Char++-- | Determines whether a 'Natural' is in the range 0 to 9.+isD10Nat :: Natural -> Bool+isD10Nat x = x <= 9++-- | Determines whether an 'Integer' is in the range 0 to 9.+isD10Integer :: Integer -> Bool+isD10Integer x = x >= 0 && x <= 9++-- | Determines whether an 'Int' is in the range 0 to 9.+isD10Int :: Int -> Bool+isD10Int x = x >= 0 && x <= 9++-- | Determines whether a number whose type has an 'Integral'+-- instance is in the range 0 to 9.+isD10Integral :: Integral a => a -> Bool+isD10Integral x = isD10Integer (toInteger x)
+ src/D10/Safe.hs view
@@ -0,0 +1,110 @@+{-# language Safe #-}++{- |++Defines a 'D10' type as+@'D0' | 'D1' | 'D2' | 'D3' | 'D4' | 'D5' | 'D6' | 'D7' | 'D8' | 'D9'@.++-}++module D10.Safe+    (+    -- * Related modules+    -- $modules++    -- * Type+      D10 (..)++    -- ** Bounded+    -- $bounded++    -- ** Enum+    -- $enum++    -- * Quasi-quoters+    , d10list++    -- * Splices+    -- ** Expressions+    , d10ListExp+    -- ** Patterns+    , d10ListPat++    -- * Conversions+    -- ** D10 / Char+    , d10Char, charD10Maybe, charD10Either, charD10Fail+    -- ** D10 / String+    , d10Str, strD10Maybe, strD10Either, strD10Fail+    -- ** [D10] / String+    , strD10ListMaybe, strD10ListEither, strD10ListFail+    -- ** D10 / Natural+    , d10Nat, natD10Maybe, natD10Either, natD10Fail, natMod10+    -- ** D10 / Integer+    , d10Integer, integerD10Maybe, integerD10Either+    , integerD10Fail, integerMod10+    -- ** D10 / Int+    , d10Int, intD10Maybe, intD10Either, intD10Fail, intMod10+    -- ** D10 / general numeric types+    , d10Num, integralD10Maybe, integralD10Either+    , integralD10Fail, integralMod10+    ) where++import D10.Safe.Conversions+import D10.Safe.Quotes+import D10.Safe.Splices+import D10.Safe.Type++{- $modules++Additional functions related to this 'D10' type may be found in:++  * "D10.Safe.Arithmetic"++The contents of the following modules are re-exported here:++  * "D10.Safe.Type"+  * "D10.Safe.Conversions"+  * "D10.Safe.Quotes"+  * "D10.Safe.Splices"++The following modules define @D10@ types in different ways+but are otherwise very similar to this one:++  * "D10.Char"+  * "D10.Num"++This module is called "safe" because, in contrast with the+alternative representations of a digit defined in the other+modules, this 'D10' type does not include any possibility+of representing an invalid non-digit value.++-}++{- $bounded++-- >>> minBound :: D10+-- D0+--+-- >>> maxBound :: D10+-- D9++-}++{- $enum++>>> [ D5 .. ]+[D5,D6,D7,D8,D9]++>>> [ D4 .. D7 ]+[D4,D5,D6,D7]++>>> [ D5, D4 .. ]+[D5,D4,D3,D2,D1,D0]++>>> [ D1, D3 .. ]+[D1,D3,D5,D7,D9]++>>> [ minBound .. maxBound ] :: [D10]+[D0,D1,D2,D3,D4,D5,D6,D7,D8,D9]++-}
+ src/D10/Safe/Arithmetic.hs view
@@ -0,0 +1,39 @@+{-# language Safe #-}++module D10.Safe.Arithmetic where++import D10.Safe (D10, d10Int, intMod10)++import qualified Prelude as P++-- | Addition modulo 10.+--+-- >>> D2 + D3+-- D5+--+-- >>> D6 + D7+-- D3++(+) :: D10 -> D10 -> D10+x + y = intMod10 (d10Int x P.+ d10Int y)++-- | Subtraction modulo 10.+--+-- >>> D7 - D5+-- D2+--+-- >>> D3 - D7+-- D6++(-) :: D10 -> D10 -> D10+x - y = intMod10 (d10Int x P.- d10Int y)++-- | Multiplication modulo 10.+--+-- >>> D2 * D4+-- D8+-- >>> D7 * D8+-- D6++(*) :: D10 -> D10 -> D10+x * y = intMod10 (d10Int x P.* d10Int y)
+ src/D10/Safe/Conversions.hs view
@@ -0,0 +1,623 @@+{-# language Safe #-}++module D10.Safe.Conversions+    (+    -- * D10 / Char+      d10Char, charD10Maybe, charD10Either, charD10Fail+    -- * D10 / String+    , d10Str, strD10Maybe, strD10Either, strD10Fail+    -- * [D10] / String+    , strD10ListMaybe, strD10ListEither, strD10ListFail+    -- * D10 / Natural+    , d10Nat, natD10Maybe, natD10Either, natD10Fail, natMod10+    -- * D10 / Integer+    , d10Integer, integerD10Maybe, integerD10Either+    , integerD10Fail, integerMod10+    -- * D10 / Int+    , d10Int, intD10Maybe, intD10Either, intD10Fail, intMod10+    -- * D10 / general numeric types+    , d10Num, integralD10Maybe, integralD10Either+    , integralD10Fail, integralMod10+    ) where++import D10.Safe.Type (D10 (..))++-- base+import Control.Monad.Fail (MonadFail (fail))+import Numeric.Natural    (Natural)+import Prelude            hiding (fail)++-- | Convert a 'D10' to its underlying 'Char' representation.+--+-- >>> d10Char D7+-- '7'++d10Char :: D10 -> Char+d10Char x =+    case x of+        D0 -> '0'+        D1 -> '1'+        D2 -> '2'+        D3 -> '3'+        D4 -> '4'+        D5 -> '5'+        D6 -> '6'+        D7 -> '7'+        D8 -> '8'+        D9 -> '9'++-- | Convert a 'D10' to a 'String'.+--+-- @'d10Str' x = ['d10Char' x]@+--+-- >>> d10Str D7+-- "7"++d10Str :: D10 -> String+d10Str x = [d10Char x]++-- | Convert a 'D10' to a 'Natural'.+--+-- 'd10Num' is a more general version of this function.+--+-- >>> d10Nat D7+-- 7++d10Nat :: D10 -> Natural+d10Nat = d10Num++-- | Convert a 'D10' to an 'Integer'.+--+-- 'd10Num' is a more general version of this function.+--+-- >>> d10Integer D7+-- 7++d10Integer :: D10 -> Integer+d10Integer = d10Num++-- | Convert a 'D10' to an 'Int'.+--+-- 'd10Num' is a more general version of this function.+--+-- >>> d10Int D7+-- 7++d10Int :: D10 -> Int+d10Int = d10Num++-- | Convert a 'D10' to any kind of number with a 'Num' instance.+--+-- Specialized versions of this function include 'd10Nat',+-- 'd10Integer', and 'd10Int'.+--+-- >>> d10Num D7 :: Integer+-- 7++d10Num :: Num a => D10 -> a+d10Num x =+    case x of+        D0 -> 0+        D1 -> 1+        D2 -> 2+        D3 -> 3+        D4 -> 4+        D5 -> 5+        D6 -> 6+        D7 -> 7+        D8 -> 8+        D9 -> 9++---------------------------------------------------++-- | The 'D10' which is uniquely congruent modulo 10 to the given 'Natural'.+--+-- 'integralMod10' is a more general version of this function.+--+-- >>> natMod10 56+-- D6++natMod10 :: Natural -> D10+natMod10 = integralMod10++-- | The 'D10' which is uniquely congruent modulo 10 to the given 'Integer'.+--+-- 'integralMod10' is a more general version of this function.+--+-- >>> integerMod10 56+-- D6+--+-- >>> integerMod10 (-56)+-- D4++integerMod10 :: Integer -> D10+integerMod10 = integralMod10++-- | The 'D10' which is uniquely congruent modulo 10 to the given 'Int'.+--+-- 'integralMod10' is a more general version of this function.+--+-- >>> intMod10 56+-- D6+--+-- >>> intMod10 (-56)+-- D4++intMod10 :: Int -> D10+intMod10 = integralMod10++-- | The 'D10' which is uniquely congruent modulo 10 to the given number+-- (whose type must have an instance of the 'Integral' class).+--+-- Specialized versions of this function include 'natMod10',+-- 'integerMod10', and 'intMod10'.+--+-- >>> integralMod10 (56 :: Integer)+-- D6+--+-- >>> integralMod10 ((-56) :: Integer)+-- D4++integralMod10 :: Integral a => a -> D10+integralMod10 x =+    case (x `mod` 10) of+        0 -> D0+        1 -> D1+        2 -> D2+        3 -> D3+        4 -> D4+        5 -> D5+        6 -> D6+        7 -> D7+        8 -> D8+        9 -> D9+        _ -> error "x `mod` 10 is not between 0 and 9"++---------------------------------------------------++-- | Convert a 'Char' to a 'D10' if it is within the range+-- @'0'@ to @'9'@, or produce 'Nothing' otherwise.+--+-- @'D10.Predicate.isD10Char' x = 'Data.Maybe.isJust' ('charD10Maybe' x)@+--+-- 'charD10Fail' is a more general version of this function.+--+-- >>> charD10Maybe '5'+-- Just D5+--+-- >>> charD10Maybe 'a'+-- Nothing++charD10Maybe :: Char -> Maybe D10+charD10Maybe x =+    case x of+        '0' -> Just D0+        '1' -> Just D1+        '2' -> Just D2+        '3' -> Just D3+        '4' -> Just D4+        '5' -> Just D5+        '6' -> Just D6+        '7' -> Just D7+        '8' -> Just D8+        '9' -> Just D9+        _   -> Nothing++-- | Convert a 'String' to a 'D10' if it consists of exactly one+-- character and that character is within the range @'0'@ to @'9'@,+-- or produce 'Nothing' otherwise.+--+-- @'D10.Predicate.isD10Str' x = 'Data.Maybe.isJust' ('strD10Maybe' x)@+--+-- 'strD10Fail' is a more general version of this function.+--+-- >>> strD10Maybe "5"+-- Just D5+--+-- >>> strD10Maybe "a"+-- Nothing+--+-- >>> strD10Maybe "58"+-- Nothing++strD10Maybe :: String -> Maybe D10+strD10Maybe [x] = charD10Maybe x+strD10Maybe _   = Nothing++-- | Convert a 'String' to a list of 'D10' if all of the characters+-- in the string are within the range @'0'@ to @'9'@, or produce+-- 'Nothing' otherwise.+--+-- @'D10.Predicate.isD10ListStr' x = 'Data.Maybe.isJust' ('strD10ListMaybe' x)@+--+-- 'strD10ListFail' is a more general version of this function.+--+-- >>> strD10ListMaybe "5"+-- Just [D5]+--+-- >>> strD10ListMaybe "a"+-- Nothing+--+-- >>> strD10ListMaybe "58"+-- Just [D5,D8]++strD10ListMaybe :: String -> Maybe [D10]+strD10ListMaybe = traverse charD10Maybe++-- | Convert a 'Natural' to a 'D10' if it is less than 10,+-- or produce 'Nothing' otherwise.+--+-- @'D10.Predicate.isD10Nat' x = 'Data.Maybe.isJust' ('natD10Maybe' x)@+--+-- 'integralD10Maybe', 'natD10Fail', and 'integralD10Fail'+-- are more general versions of this function.+--+-- >>> natD10Maybe 5+-- Just D5+--+-- >>> natD10Maybe 12+-- Nothing++natD10Maybe :: Natural -> Maybe D10+natD10Maybe = integralD10Maybe++-- | Convert an 'Integer' to a 'D10' if it is within the range 0 to 9,+-- or produce 'Nothing' otherwise.+--+-- @'D10.Predicate.isD10Integer' x = 'Data.Maybe.isJust' ('integerD10Maybe' x)@+--+-- 'integralD10Maybe', 'integerD10Fail', and 'integralD10Fail'+-- are more general versions of this function.+--+-- >>> integerD10Maybe 5+-- Just D5+--+-- >>> integerD10Maybe 12+-- Nothing+--+-- >>> integerD10Maybe (-5)+-- Nothing++integerD10Maybe :: Integer -> Maybe D10+integerD10Maybe = integralD10Maybe++-- | Convert an 'Int' to a 'D10' if it is within the range 0 to 9,+-- or produce 'Nothing' otherwise.+--+-- @'D10.Predicate.isD10Int' x = 'Data.Maybe.isJust' ('intD10Maybe' x)@+--+-- 'integralD10Maybe', 'intD10Fail', and 'integralD10Fail'+-- are more general versions of this function.+--+-- >>> intD10Maybe 5+-- Just D5+--+-- >>> intD10Maybe 12+-- Nothing+--+-- >>> intD10Maybe (-5)+-- Nothing++intD10Maybe :: Int -> Maybe D10+intD10Maybe = integralD10Maybe++-- | Construct a 'D10' from any kind of number with an 'Integral'+-- instance, or produce 'Nothing' if the number falls outside the+-- range 0 to 9.+--+-- @'D10.Predicate.isD10Integral' x = 'Data.Maybe.isJust' ('integralD10Maybe' x)@+--+-- Specialized versions of this function include 'natD10Maybe',+-- 'integerD10Maybe', and 'intD10Maybe'.+--+-- 'integralD10Fail' is a more general version of this function.+--+-- >>> integralD10Maybe (5 :: Integer)+-- Just D5+--+-- >>> integralD10Maybe (12 :: Integer)+-- Nothing+--+-- >>> integralD10Maybe ((-5) :: Integer)+-- Nothing++integralD10Maybe :: Integral a => a -> Maybe D10+integralD10Maybe x =+    case x of+        0 -> Just D0+        1 -> Just D1+        2 -> Just D2+        3 -> Just D3+        4 -> Just D4+        5 -> Just D5+        6 -> Just D6+        7 -> Just D7+        8 -> Just D8+        9 -> Just D9+        _ -> Nothing++---------------------------------------------------++-- | Convert a 'Char' to a 'D10' if it is within the range+-- @'0'@ to @'9'@, or 'Left' with an error message otherwise.+--+-- >>> charD10Either '5'+-- Right D5+--+-- >>> charD10Either 'a'+-- Left "d10 must be between 0 and 9"++charD10Either :: Char -> Either String D10+charD10Either x =+    case x of+        '0' -> Right D0+        '1' -> Right D1+        '2' -> Right D2+        '3' -> Right D3+        '4' -> Right D4+        '5' -> Right D5+        '6' -> Right D6+        '7' -> Right D7+        '8' -> Right D8+        '9' -> Right D9+        _   -> Left "d10 must be between 0 and 9"++-- | Convert a 'String' to a 'D10' if it consists of a single+-- character and that character is within the range @'0'@ to+-- @'9'@, or 'Left' with an error message otherwise.+--+-- >>> strD10Either "5"+-- Right D5+--+-- >>> strD10Either "a"+-- Left "d10 must be between 0 and 9"+--+-- >>> strD10Either "58"+-- Left "d10 must be a single character"++strD10Either :: String -> Either String D10+strD10Either [x] = charD10Either x+strD10Either _   = Left "d10 must be a single character"++-- | Convert a 'String' to a 'D10' if all of the characters in+-- the string fall within the range @'0'@ to @'9'@, or 'Left'+-- with an error message otherwise.+--+-- >>> strD10ListEither "5"+-- Right [D5]+--+-- >>> strD10ListEither "a"+-- Left "d10 must be between 0 and 9"+--+-- >>> strD10ListEither "58"+-- Right [D5,D8]++strD10ListEither :: String -> Either String [D10]+strD10ListEither = traverse charD10Either++-- | Convert a 'Natural' to a 'D10' if it is less than 10,+-- or 'Left' with an error message otherwise.+--+-- >>> natD10Either 5+-- Right D5+--+-- >>> natD10Either 12+-- Left "d10 must be less than 10"++natD10Either :: Natural -> Either String D10+natD10Either x =+    case x of+        0 -> Right D0+        1 -> Right D1+        2 -> Right D2+        3 -> Right D3+        4 -> Right D4+        5 -> Right D5+        6 -> Right D6+        7 -> Right D7+        8 -> Right D8+        9 -> Right D9+        _ -> Left "d10 must be less than 10"++-- | Convert an 'Integer' to a 'D10' if it is within the+-- range 0 to 9, or 'Left' with an error message otherwise.+--+-- >>> integerD10Either 5+-- Right D5+--+-- >>> integerD10Either 12+-- Left "d10 must be between 0 and 9"+--+-- >>> integerD10Either (-5)+-- Left "d10 must be between 0 and 9"++integerD10Either :: Integer -> Either String D10+integerD10Either = integralD10Either++-- | Convert an 'Int' to a 'D10' if it is within the range+-- 0 to 9, or 'Left' with an error message otherwise.+--+-- >>> intD10Either 5+-- Right D5+--+-- >>> intD10Either 12+-- Left "d10 must be between 0 and 9"+--+-- >>> intD10Either (-5)+-- Left "d10 must be between 0 and 9"++intD10Either :: Int -> Either String D10+intD10Either = integralD10Either++-- | Convert a number of a type that has an 'Integral' instance+-- to a 'D10' if it falls within the range 0 to 9, or 'Left'+-- with an error message otherwise.+--+-- >>> integralD10Either (5 :: Integer)+-- Right D5+--+-- >>> integralD10Either (12 :: Integer)+-- Left "d10 must be between 0 and 9"+--+-- >>> integralD10Either ((-5) :: Integer)+-- Left "d10 must be between 0 and 9"++integralD10Either :: Integral a => a -> Either String D10+integralD10Either x =+    case (integralD10Maybe x) of+        Just y  -> Right y+        Nothing -> Left "d10 must be between 0 and 9"++---------------------------------------------------++-- | Convert a 'Char' to a 'D10' if it is within the range+-- @'0'@ to @'9'@, or 'fail' with an error message otherwise.+--+-- 'charD10Maybe' is a specialized version of this function.+--+-- >>> charD10Fail '5' :: IO D10+-- D5+--+-- >>> charD10Fail 'a' :: IO D10+-- *** Exception: user error (d10 must be between 0 and 9)++charD10Fail :: MonadFail m => Char -> m D10+charD10Fail x =+    case x of+        '0' -> return D0+        '1' -> return D1+        '2' -> return D2+        '3' -> return D3+        '4' -> return D4+        '5' -> return D5+        '6' -> return D6+        '7' -> return D7+        '8' -> return D8+        '9' -> return D9+        _   -> fail "d10 must be between 0 and 9"++-- | Convert a 'String' to a 'D10' if it consists of a single+-- character and that character is within the range @'0'@ to+-- @'9'@, or 'fail' with an error message otherwise.+--+-- 'strD10Maybe' is a specialized version of this function.+--+-- >>> strD10Fail "5" :: IO D10+-- D5+--+-- >>> strD10Fail "a" :: IO D10+-- *** Exception: user error (d10 must be between 0 and 9)+--+-- >>> strD10Fail "58" :: IO D10+-- *** Exception: user error (d10 must be a single character)++strD10Fail :: MonadFail m => String -> m D10+strD10Fail [x] = charD10Fail x+strD10Fail _   = fail "d10 must be a single character"++-- | Convert a 'String' to a 'D10' if all of the characters in+-- the string fall within the range @'0'@ to @'9'@, or 'fail'+-- with an error message otherwise.+--+-- 'strD10ListMaybe' is a specialized version of this function.+--+-- >>> strD10ListFail "5" :: IO [D10]+-- [D5]+--+-- >>> strD10ListFail "a" :: IO [D10]+-- *** Exception: user error (d10 must be between 0 and 9)+--+-- >>> strD10ListFail "58" :: IO [D10]+-- [D5,D8]++strD10ListFail :: MonadFail m => String -> m [D10]+strD10ListFail = traverse charD10Fail++-- | Convert a 'Natural' to a 'D10' if it is less than 10,+-- or 'fail' with an error message otherwise.+--+-- 'natD10Maybe' is a specialized version of this function.+--+-- 'integralD10Fail' is a more general version of this function.+--+-- >>> natD10Fail 5 :: IO D10+-- D5+--+-- >>> natD10Fail 12 :: IO D10+-- *** Exception: user error (d10 must be less than 10)++natD10Fail :: MonadFail m => Natural -> m D10+natD10Fail x =+    case x of+        0 -> return D0+        1 -> return D1+        2 -> return D2+        3 -> return D3+        4 -> return D4+        5 -> return D5+        6 -> return D6+        7 -> return D7+        8 -> return D8+        9 -> return D9+        _ -> fail "d10 must be less than 10"++-- | Convert an 'Integer' to a 'D10' if it is within the+-- range 0 to 9, or 'fail' with an error message otherwise.+--+-- 'integerD10Maybe' is a specialized version of this function.+--+-- 'integralD10Fail' is a more general version of this function.+--+-- >>> integerD10Fail 5 :: IO D10+-- D5+--+-- >>> integerD10Fail 12 :: IO D10+-- *** Exception: user error (d10 must be between 0 and 9)+--+-- >>> integerD10Fail (-5) :: IO D10+-- *** Exception: user error (d10 must be between 0 and 9)++integerD10Fail :: MonadFail m => Integer -> m D10+integerD10Fail = integralD10Fail++-- | Convert an 'Int' to a 'D10' if it is within the range+-- 0 to 9, or 'fail' with an error message otherwise.+--+-- 'intD10Maybe' is a specialized version of this function.+--+-- 'integralD10Fail' is a more general version of this function.+--+-- >>> intD10Fail 5 :: IO D10+-- D5+--+-- >>> intD10Fail 12 :: IO D10+-- *** Exception: user error (d10 must be between 0 and 9)+--+-- >>> intD10Fail (-5) :: IO D10+-- *** Exception: user error (d10 must be between 0 and 9)++intD10Fail :: MonadFail m => Int -> m D10+intD10Fail = integralD10Fail++-- | Convert a number of a type that has an 'Integral' instance+-- to a 'D10' if it falls within the range 0 to 9, or 'fail'+-- with an error message otherwise.+--+-- 'natD10Maybe', 'integerD10Maybe', 'intD10Maybe',+-- 'integralD10Maybe', 'natD10Fail', 'integerD10Fail', and+-- 'intD10Fail' are all specialized versions of this function.+--+-- >>> integralD10Fail (5 :: Integer) :: IO D10+-- D5+--+-- >>> integralD10Fail (12 :: Integer) :: IO D10+-- *** Exception: user error (d10 must be between 0 and 9)+--+-- >>> integralD10Fail ((-5) :: Integer) :: IO D10+-- *** Exception: user error (d10 must be between 0 and 9)++integralD10Fail :: (Integral a, MonadFail m) => a -> m D10+integralD10Fail x =+    case (integralD10Maybe x) of+        Just y  -> return y+        Nothing -> fail "d10 must be between 0 and 9"
+ src/D10/Safe/Quotes.hs view
@@ -0,0 +1,56 @@+{-# language Safe #-}++module D10.Safe.Quotes (d10list) where++import D10.Safe.Splices++import Control.Monad.Fail (MonadFail (fail))+import Language.Haskell.TH.Quote (QuasiQuoter (..))+import Prelude hiding (fail)++-- | A list of base-10 digits.+--+-- This quasi-quoter, when used as an expression, produces a+-- value of type @['D10']@.+--+-- >>> [d10list||]+-- []+--+-- >>> [d10list|5|]+-- [D5]+--+-- >>> [d10list|58|]+-- [D5,D8]+--+-- >>> [d10list|a|]+-- ...+-- ... d10 must be between 0 and 9+-- ...+--+-- This quasi-quoter can also be used as a pattern.+--+-- >>> :{+--       case [D5, D6] of+--         [d10list|41|] -> "A"+--         [d10list|56|] -> "B"+--         _             -> "C"+-- >>> :}+-- "B"+--+-- >>> :{+--       case [D5, D6] of+--         [d10list|4x|] -> "A"+--         [d10list|56|] -> "B"+--         _             -> "C"+-- >>> :}+-- ...+-- ... d10 must be between 0 and 9+-- ...++d10list :: QuasiQuoter+d10list = QuasiQuoter+    { quoteExp  = d10ListExp+    , quotePat  = d10ListPat+    , quoteType = \_ -> fail "d10list cannot be used in a type context"+    , quoteDec  = \_ -> fail "d10list cannot be used in a declaration context"+    }
+ src/D10/Safe/Splices.hs view
@@ -0,0 +1,59 @@+{-# language Safe #-}++module D10.Safe.Splices+    (+    -- * Splice expressions+      d10ListExp+    -- * Splice patterns+    , d10ListPat+    ) where++import D10.Safe.Conversions (strD10ListFail)++import Control.Monad ((>=>))+import Language.Haskell.TH.Syntax (Exp (..), Pat (..), Q, dataToExpQ, dataToPatQ)++-- | Produces an expression of type @['D10']@ that can be used+-- in a Template Haskell splice.+--+-- >>> $(d10ListExp "")+-- []+--+-- >>> $(d10ListExp "5")+-- [D5]+--+-- >>> $(d10ListExp "58")+-- [D5,D8]+--+-- >>> $(d10ListExp "a")+-- ...+-- ... d10 must be between 0 and 9+-- ...+--+-- You may also be interested in 'D10.Safe.Quotes.d10list',+-- a quasi-quoter which does something similar.++d10ListExp :: String -> Q Exp+d10ListExp = strD10ListFail >=> dataToExpQ (const Nothing)++---------------------------------------------------++-- | Produces a pattern that can be used in a splice+-- to match a particular list of 'D10' values.+--+-- >>> :{+--       case [D5, D6] of+--         $(d10ListPat "42") -> "A"+--         $(d10ListPat "56") -> "B"+--         _                  -> "C"+-- >>> :}+-- "B"+--+-- You may also be interested in 'D10.Safe.Quotes.d10list',+-- a quasi-quoter which does something similar.++d10ListPat :: String -> Q Pat+d10ListPat = strD10ListFail >=> \xs ->+  do+    pats <- traverse (dataToPatQ (const Nothing)) xs+    return (ListP pats)
+ src/D10/Safe/Type.hs view
@@ -0,0 +1,20 @@+{-# language Safe #-}++module D10.Safe.Type (D10 (..)) where++import Data.Data (Data)+import GHC.Generics (Generic)++-- | A whole number between /0/ and /9/+data D10+    = D0  -- ^ Zero+    | D1  -- ^ One+    | D2  -- ^ Two+    | D3  -- ^ Three+    | D4  -- ^ Four+    | D5  -- ^ Five+    | D6  -- ^ Six+    | D7  -- ^ Seven+    | D8  -- ^ Eight+    | D9  -- ^ Nine+    deriving (Bounded, Enum, Eq, Ord, Show, Data, Generic)
− src/Data/D10/Char.hs
@@ -1,917 +0,0 @@--- | Defines a 'D10' type as a newtype for 'Char', where the--- values are restricted to characters between @'0'@ and @'9'@.------ The following modules define @D10@ types in different ways--- but are otherwise very similar to this one:------ * "Data.D10.Num"--- * "Data.D10.Safe"--module Data.D10.Char-    (-    -- * Type-      D10 (..)-    -- $bounded-    -- $enum--    -- * Quasi-quoters-    , d10-    , d10list--    -- * Splice expressions-    , d10Exp-    , d10ListExp--    -- * Splice patterns-    , d10Pat-    , d10ListPat--    -- * Converting between D10 and Char-    , d10Char-    , charD10Maybe-    , charD10Either-    , charD10Fail--    -- * Converting between D10 and String-    , d10Str-    , strD10Maybe-    , strD10Either-    , strD10Fail--    -- * Converting between [D10] and String-    , strD10ListMaybe-    , strD10ListEither-    , strD10ListFail--    -- * Converting between D10 and Natural-    , d10Nat-    , natD10Maybe-    , natD10Either-    , natD10Fail-    , natMod10--    -- * Converting between D10 and Integer-    , d10Integer-    , integerD10Maybe-    , integerD10Either-    , integerD10Fail-    , integerMod10--    -- * Converting between D10 and Int-    , d10Int-    , intD10Maybe-    , intD10Either-    , intD10Fail-    , intMod10--    -- * Converting between D10 and general numeric types-    , d10Num-    , integralD10Maybe-    , integralD10Either-    , integralD10Fail-    , integralMod10--    -- * Modular arithmetic-    , (+), (-), (*)--    ) where--import Data.D10.Predicate---- base-import Control.Monad      ((>=>))-import Control.Monad.Fail (MonadFail (fail))-import Data.Char          (chr, ord)-import Data.Monoid        (Endo (..))-import Numeric.Natural    (Natural)-import Prelude            hiding (fail, (+), (-), (*))--import qualified Prelude as P---- template-haskell-import Language.Haskell.TH.Lib    (litP, charL)-import Language.Haskell.TH.Quote  (QuasiQuoter (..))-import Language.Haskell.TH.Syntax (Exp (..), Lift, Pat (..), Q)--------------------------------------------------------- | A 'Char' value between @'0'@ and @'9'@.------ The "Data.D10.Char" module provides many functions for--- constructing 'D10' values, including:------ * @'integerD10Maybe' :: 'Integer' -> 'Maybe' 'D10'@--- * @'integerMod10' :: 'Integer' -> 'D10'@------ With the @QuasiQuotes@ GHC extension enabled, you can write--- 'D10' literals using the quasi-quoters 'd10' and 'd10list'.--newtype D10 =-    D10_Unsafe Char-      -- ^ 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 (Eq, Ord, Lift)---- $bounded--- ==== Bounded------ >>> minBound :: D10--- [d10|0|]------ >>> maxBound :: D10--- [d10|9|]--instance Bounded D10-  where-    minBound = D10_Unsafe '0'-    maxBound = D10_Unsafe '9'---- $enum--- ==== Enum------ >>> [ [d10|5|] .. ]--- [d10list|56789|]------ >>> [ [d10|4|] .. [d10|7|] ]--- [d10list|4567|]------ >>> [ [d10|5|], [d10|4|] .. ]--- [d10list|543210|]------ >>> [ [d10|1|], [d10|3|] .. ]--- [d10list|13579|]------ >>> [ minBound .. maxBound ] :: [D10]--- [d10list|0123456789|]--instance Enum D10-  where-    fromEnum :: D10 -> Int-    fromEnum = d10Int--    toEnum :: Int -> D10-    toEnum = either error id . intD10Either--    enumFrom :: D10 -> [D10]-    enumFrom x = enumFromTo x maxBound--    enumFromThen :: D10 -> D10 -> [D10]-    enumFromThen x y = enumFromThenTo x y bound-      where-        bound | fromEnum y >= fromEnum x = maxBound-              | otherwise                = minBound--    succ :: D10 -> D10-    succ (D10_Unsafe '9') = error "D10 overflow"-    succ (D10_Unsafe x) = D10_Unsafe (succ x)--    pred :: D10 -> D10-    pred (D10_Unsafe '0') = error "D10 underflow"-    pred (D10_Unsafe x) = D10_Unsafe (pred x)--------------------------------------------------------- | Shows base-10 digits using the quasiquoters defined in--- "Data.D10.Char". A single digit is displayed using 'd10'.--- A list of digits is displayed using 'd10list'.--instance Show D10 where-    showsPrec _ x = showString "[d10|"     . showsChar x . showString "|]"-    showList xs   = showString "[d10list|" . showsStr xs . showString "|]"--showsChar :: D10 -> ShowS-showsChar (D10_Unsafe x) = showChar x--showsStr :: [D10] -> ShowS-showsStr = appEndo . foldMap (Endo . showsChar)--------------------------------------------------------- | Convert a 'D10' to its underlying 'Char' representation.------ >>> d10Char [d10|7|]--- '7'--d10Char :: D10 -> Char-d10Char (D10_Unsafe x) = x---- | Convert a 'D10' to a 'String'.------ @'d10Str' x = ['d10Char' x]@------ >>> d10Str [d10|7|]--- "7"--d10Str :: D10 -> String-d10Str (D10_Unsafe x) = [x]---- | Convert a 'D10' to a 'Natural'.------ 'd10Num' is a more general version of this function.------ >>> d10Nat [d10|7|]--- 7--d10Nat :: D10 -> Natural-d10Nat (D10_Unsafe x) = fromIntegral (ord x P.- ord '0')---- | Convert a 'D10' to an 'Integer'.------ 'd10Num' is a more general version of this function.------ >>> d10Integer [d10|7|]--- 7--d10Integer :: D10 -> Integer-d10Integer (D10_Unsafe x) = toInteger (ord x P.- ord '0')---- | Convert a 'D10' to an 'Int'.------ 'd10Num' is a more general version of this function.------ >>> d10Int [d10|7|]--- 7--d10Int :: D10 -> Int-d10Int (D10_Unsafe x) = ord x P.- ord '0'---- | Convert a 'D10' to any kind of number with a 'Num' instance.------ Specialized versions of this function include 'd10Nat',--- 'd10Integer', and 'd10Int'.------ >>> d10Num [d10|7|] :: Integer--- 7--d10Num :: Num a => D10 -> a-d10Num (D10_Unsafe x) = fromIntegral (ord x P.- ord '0')--------------------------------------------------------- | The 'D10' which is uniquely congruent modulo 10 to the given 'Natural'.------ 'integralMod10' is a more general version of this function.------ >>> natMod10 56--- [d10|6|]--natMod10 :: Natural -> D10-natMod10 x = D10_Unsafe (chr (ord '0' P.+ fromIntegral (x `mod` 10)))---- | The 'D10' which is uniquely congruent modulo 10 to the given 'Integer'.------ 'integralMod10' is a more general version of this function.------ >>> integerMod10 56--- [d10|6|]------ >>> integerMod10 (-56)--- [d10|4|]--integerMod10 :: Integer -> D10-integerMod10 x = D10_Unsafe (chr (ord '0' P.+ fromInteger (x `mod` 10)))---- | The 'D10' which is uniquely congruent modulo 10 to the given 'Int'.------ 'integralMod10' is a more general version of this function.------ >>> intMod10 56--- [d10|6|]------ >>> intMod10 (-56)--- [d10|4|]--intMod10 :: Int -> D10-intMod10 x = D10_Unsafe (chr (ord '0' P.+ (x `mod` 10)))---- | The 'D10' which is uniquely congruent modulo 10 to the given number--- (whose type must have an instance of the 'Integral' class).------ Specialized versions of this function include 'natMod10',--- 'integerMod10', and 'intMod10'.------ >>> integralMod10 (56 :: Integer)--- [d10|6|]------ >>> integralMod10 ((-56) :: Integer)--- [d10|4|]--integralMod10 :: Integral a => a -> D10-integralMod10 x = D10_Unsafe (chr (ord '0' P.+ fromIntegral (x `mod` 10)))--------------------------------------------------------- | Convert a 'Char' to a 'D10' if it is within the range--- @'0'@ to @'9'@, or produce 'Nothing' otherwise.------ @'Data.D10.Predicate.isD10Char' x = 'Data.Maybe.isJust' ('charD10Maybe' x)@------ 'charD10Fail' is a more general version of this function.------ >>> charD10Maybe '5'--- Just [d10|5|]------ >>> charD10Maybe 'a'--- Nothing--charD10Maybe :: Char -> Maybe D10-charD10Maybe x-        | isD10Char x  =  Just (D10_Unsafe x)-        | otherwise    =  Nothing---- | Convert a 'String' to a 'D10' if it consists of exactly one--- character and that character is within the range @'0'@ to @'9'@,--- or produce 'Nothing' otherwise.------ @'Data.D10.Predicate.isD10Str' x = 'Data.Maybe.isJust' ('strD10Maybe' x)@------ 'strD10Fail' is a more general version of this function.------ >>> strD10Maybe "5"--- Just [d10|5|]------ >>> strD10Maybe "a"--- Nothing------ >>> strD10Maybe "58"--- Nothing--strD10Maybe :: String -> Maybe D10-strD10Maybe [x] = charD10Maybe x-strD10Maybe _   = Nothing---- | Convert a 'String' to a list of 'D10' if all of the characters--- in the string are within the range @'0'@ to @'9'@, or produce--- 'Nothing' otherwise.------ @'Data.D10.Predicate.isD10ListStr' x = 'Data.Maybe.isJust' ('strD10ListMaybe' x)@------ 'strD10ListFail' is a more general version of this function.------ >>> strD10ListMaybe "5"--- Just [d10list|5|]------ >>> strD10ListMaybe "a"--- Nothing------ >>> strD10ListMaybe "58"--- Just [d10list|58|]--strD10ListMaybe :: String -> Maybe [D10]-strD10ListMaybe = traverse charD10Maybe---- | Convert a 'Natural' to a 'D10' if it is less than 10,--- or produce 'Nothing' otherwise.------ @'Data.D10.Predicate.isD10Nat' x = 'Data.Maybe.isJust' ('natD10Maybe' x)@------ 'integralD10Maybe', 'natD10Fail', and 'integralD10Fail'--- are more general versions of this function.------ >>> natD10Maybe 5--- Just [d10|5|]------ >>> natD10Maybe 12--- Nothing--natD10Maybe :: Natural -> Maybe D10-natD10Maybe x-        | isD10Nat x  =  Just (D10_Unsafe (chr (fromIntegral x P.+ ord '0')))-        | otherwise   =  Nothing---- | Convert an 'Integer' to a 'D10' if it is within the range 0 to 9,--- or produce 'Nothing' otherwise.------ @'Data.D10.Predicate.isD10Integer' x = 'Data.Maybe.isJust' ('integerD10Maybe' x)@------ 'integralD10Maybe', 'integerD10Fail', and 'integralD10Fail'--- are more general versions of this function.------ >>> integerD10Maybe 5--- Just [d10|5|]------ >>> integerD10Maybe 12--- Nothing------ >>> integerD10Maybe (-5)--- Nothing--integerD10Maybe :: Integer -> Maybe D10-integerD10Maybe x-        | isD10Integer x  =  Just (D10_Unsafe (chr (fromInteger x P.+ ord '0')))-        | otherwise       =  Nothing---- | Convert an 'Int' to a 'D10' if it is within the range 0 to 9,--- or produce 'Nothing' otherwise.------ @'Data.D10.Predicate.isD10Int' x = 'Data.Maybe.isJust' ('intD10Maybe' x)@------ 'integralD10Maybe', 'intD10Fail', and 'integralD10Fail'--- are more general versions of this function.------ >>> intD10Maybe 5--- Just [d10|5|]------ >>> intD10Maybe 12--- Nothing------ >>> intD10Maybe (-5)--- Nothing--intD10Maybe :: Int -> Maybe D10-intD10Maybe x-        | isD10Int x  =  Just (D10_Unsafe (chr (x P.+ ord '0')))-        | otherwise   =  Nothing---- | Construct a 'D10' from any kind of number with an 'Integral'--- instance, or produce 'Nothing' if the number falls outside the--- range 0 to 9.------ @'Data.D10.Predicate.isD10Integral' x = 'Data.Maybe.isJust' ('integralD10Maybe' x)@------ Specialized versions of this function include 'natD10Maybe',--- 'integerD10Maybe', and 'intD10Maybe'.------ 'integralD10Fail' is a more general version of this function.------ >>> integralD10Maybe (5 :: Integer)--- Just [d10|5|]------ >>> integralD10Maybe (12 :: Integer)--- Nothing------ >>> integralD10Maybe ((-5) :: Integer)--- Nothing--integralD10Maybe :: Integral a => a -> Maybe D10-integralD10Maybe x = integerD10Maybe (toInteger x)--------------------------------------------------------- | Convert a 'Char' to a 'D10' if it is within the range--- @'0'@ to @'9'@, or 'Left' with an error message otherwise.------ >>> charD10Either '5'--- Right [d10|5|]------ >>> charD10Either 'a'--- Left "d10 must be between 0 and 9"--charD10Either :: Char -> Either String D10-charD10Either x-        | isD10Char x  =  Right (D10_Unsafe x)-        | otherwise    =  Left "d10 must be between 0 and 9"---- | Convert a 'String' to a 'D10' if it consists of a single--- character and that character is within the range @'0'@ to--- @'9'@, or 'Left' with an error message otherwise.------ >>> strD10Either "5"--- Right [d10|5|]------ >>> strD10Either "a"--- Left "d10 must be between 0 and 9"------ >>> strD10Either "58"--- Left "d10 must be a single character"--strD10Either :: String -> Either String D10-strD10Either [x]         =  charD10Either x-strD10Either _           =  Left "d10 must be a single character"---- | Convert a 'String' to a 'D10' if all of the characters in--- the string fall within the range @'0'@ to @'9'@, or 'Left'--- with an error message otherwise.------ >>> strD10ListEither "5"--- Right [d10list|5|]------ >>> strD10ListEither "a"--- Left "d10 must be between 0 and 9"------ >>> strD10ListEither "58"--- Right [d10list|58|]--strD10ListEither :: String -> Either String [D10]-strD10ListEither = traverse charD10Either---- | Convert a 'Natural' to a 'D10' if it is less than 10,--- or 'Left' with an error message otherwise.------ >>> natD10Either 5--- Right [d10|5|]------ >>> natD10Either 12--- Left "d10 must be less than 10"--natD10Either :: Natural -> Either String D10-natD10Either x =-    case (natD10Maybe x) of-        Just y  -> Right y-        Nothing -> Left "d10 must be less than 10"---- | Convert an 'Integer' to a 'D10' if it is within the--- range 0 to 9, or 'Left' with an error message otherwise.------ >>> integerD10Either 5--- Right [d10|5|]------ >>> integerD10Either 12--- Left "d10 must be between 0 and 9"------ >>> integerD10Either (-5)--- Left "d10 must be between 0 and 9"--integerD10Either :: Integer -> Either String D10-integerD10Either x =-    case (integerD10Maybe x) of-        Just y  -> Right y-        Nothing -> Left "d10 must be between 0 and 9"---- | Convert an 'Int' to a 'D10' if it is within the range--- 0 to 9, or 'Left' with an error message otherwise.------ >>> intD10Either 5--- Right [d10|5|]------ >>> intD10Either 12--- Left "d10 must be between 0 and 9"------ >>> intD10Either (-5)--- Left "d10 must be between 0 and 9"--intD10Either :: Int -> Either String D10-intD10Either x =-    case (intD10Maybe x) of-        Just y  ->  Right y-        Nothing ->  Left "d10 must be between 0 and 9"---- | Convert a number of a type that has an 'Integral' instance--- to a 'D10' if it falls within the range 0 to 9, or 'Left'--- with an error message otherwise.------ >>> integralD10Either (5 :: Integer)--- Right [d10|5|]------ >>> integralD10Either (12 :: Integer)--- Left "d10 must be between 0 and 9"------ >>> integralD10Either ((-5) :: Integer)--- Left "d10 must be between 0 and 9"--integralD10Either :: Integral a => a -> Either String D10-integralD10Either x = integerD10Either (toInteger x)--------------------------------------------------------- | Convert a 'Char' to a 'D10' if it is within the range--- @'0'@ to @'9'@, or 'fail' with an error message otherwise.------ 'charD10Maybe' is a specialized version of this function.------ >>> charD10Fail '5' :: IO D10--- [d10|5|]------ >>> charD10Fail 'a' :: IO D10--- *** Exception: user error (d10 must be between 0 and 9)--charD10Fail :: MonadFail m => Char -> m D10-charD10Fail x-        | isD10Char x  =  return (D10_Unsafe x)-        | otherwise    =  fail "d10 must be between 0 and 9"---- | Convert a 'String' to a 'D10' if it consists of a single--- character and that character is within the range @'0'@ to--- @'9'@, or 'fail' with an error message otherwise.------ 'strD10Maybe' is a specialized version of this function.------ >>> strD10Fail "5" :: IO D10--- [d10|5|]------ >>> strD10Fail "a" :: IO D10--- *** Exception: user error (d10 must be between 0 and 9)------ >>> strD10Fail "58" :: IO D10--- *** Exception: user error (d10 must be a single character)--strD10Fail :: MonadFail m => String -> m D10-strD10Fail [x]         =  charD10Fail x-strD10Fail _           =  fail "d10 must be a single character"---- | Convert a 'String' to a 'D10' if all of the characters in--- the string fall within the range @'0'@ to @'9'@, or 'fail'--- with an error message otherwise.------ 'strD10ListMaybe' is a specialized version of this function.------ >>> strD10ListFail "5" :: IO [D10]--- [d10list|5|]------ >>> strD10ListFail "a" :: IO [D10]--- *** Exception: user error (d10 must be between 0 and 9)------ >>> strD10ListFail "58" :: IO [D10]--- [d10list|58|]--strD10ListFail :: MonadFail m => String -> m [D10]-strD10ListFail = traverse charD10Fail---- | Convert a 'Natural' to a 'D10' if it is less than 10,--- or 'fail' with an error message otherwise.------ 'natD10Maybe' is a specialized version of this function.------ 'integralD10Fail' is a more general version of this function.------ >>> natD10Fail 5 :: IO D10--- [d10|5|]------ >>> natD10Fail 12 :: IO D10--- *** Exception: user error (d10 must be less than 10)--natD10Fail :: MonadFail m => Natural -> m D10-natD10Fail x =-    case (natD10Maybe x) of-        Just y  -> return y-        Nothing -> fail "d10 must be less than 10"---- | Convert an 'Integer' to a 'D10' if it is within the--- range 0 to 9, or 'fail' with an error message otherwise.------ 'integerD10Maybe' is a specialized version of this function.------ 'integralD10Fail' is a more general version of this function.------ >>> integerD10Fail 5 :: IO D10--- [d10|5|]------ >>> integerD10Fail 12 :: IO D10--- *** Exception: user error (d10 must be between 0 and 9)------ >>> integerD10Fail (-5) :: IO D10--- *** Exception: user error (d10 must be between 0 and 9)--integerD10Fail :: MonadFail m => Integer -> m D10-integerD10Fail x =-    case (integerD10Maybe x) of-        Just y  -> return y-        Nothing -> fail "d10 must be between 0 and 9"---- | Convert an 'Int' to a 'D10' if it is within the range--- 0 to 9, or 'fail' with an error message otherwise.------ 'intD10Maybe' is a specialized version of this function.------ 'integralD10Fail' is a more general version of this function.------ >>> intD10Fail 5 :: IO D10--- [d10|5|]------ >>> intD10Fail 12 :: IO D10--- *** Exception: user error (d10 must be between 0 and 9)------ >>> intD10Fail (-5) :: IO D10--- *** Exception: user error (d10 must be between 0 and 9)--intD10Fail :: MonadFail m => Int -> m D10-intD10Fail x =-    case (intD10Maybe x) of-        Just y  ->  return y-        Nothing ->  fail "d10 must be between 0 and 9"---- | Convert a number of a type that has an 'Integral' instance--- to a 'D10' if it falls within the range 0 to 9, or 'fail'--- with an error message otherwise.------ 'natD10Maybe', 'integerD10Maybe', 'intD10Maybe',--- 'integralD10Maybe', 'natD10Fail', 'integerD10Fail', and--- 'intD10Fail' are all specialized versions of this function.------ >>> integralD10Fail (5 :: Integer) :: IO D10--- [d10|5|]------ >>> integralD10Fail (12 :: Integer) :: IO D10--- *** Exception: user error (d10 must be between 0 and 9)------ >>> integralD10Fail ((-5) :: Integer) :: IO D10--- *** Exception: user error (d10 must be between 0 and 9)--integralD10Fail :: (Integral a, MonadFail m) => a -> m D10-integralD10Fail x = integerD10Fail (toInteger x)--------------------------------------------------------- | Produces an expression of type 'D10' that can be used--- in a Template Haskell splice.------ >>> d10Nat $(d10Exp 5)--- 5------ >>> d10Nat $(d10Exp 12)--- ...--- ... d10 must be between 0 and 9--- ...------ You may also be interested in 'd10', a quasi-quoter which--- does something similar.--d10Exp :: Integer -> Q Exp-d10Exp = integerD10Fail >=> d10Exp'--d10Exp' :: D10 -> Q Exp-d10Exp' x = [| x |]---- | Produces an expression of type @['D10']@ that can be used--- in a Template Haskell splice.------ >>> d10Nat <$> $(d10ListExp "")--- []------ >>> d10Nat <$> $(d10ListExp "5")--- [5]------ >>> d10Nat <$> $(d10ListExp "58")--- [5,8]------ >>> d10Nat <$> $(d10ListExp "a")--- ...--- ... d10 must be between 0 and 9--- ...------ You may also be interested in 'd10list', a quasi-quoter which--- does something similar.--d10ListExp :: String -> Q Exp-d10ListExp = strD10ListFail >=> d10ListExp'--d10ListExp' :: [D10] -> Q Exp-d10ListExp' xs = [| xs |]--------------------------------------------------------- | Produces a pattern that can be used in a splice--- to match a particular 'D10' value.------ >>> :{---       case (charD10Maybe '5') of---         Just $(d10Pat 4) -> "A"---         Just $(d10Pat 5) -> "B"---         _                -> "C"--- >>> :}--- "B"------ You may wish to use the 'd10' quasi-quoter instead.--d10Pat :: Integer -> Q Pat-d10Pat = integerD10Fail >=> d10Pat'--d10Pat' :: D10 -> Q Pat-d10Pat' (D10_Unsafe x) = [p| D10_Unsafe $(litP $ charL x) |]---- | Produces a pattern that can be used in a splice--- to match a particular list of 'D10' values.------ >>> :{---       case (strD10ListMaybe "56") of---         Just $(d10ListPat "42") -> "A"---         Just $(d10ListPat "56") -> "B"---         _                       -> "C"--- >>> :}--- "B"------ You may wish to use the 'd10list' quasi-quoter instead.--d10ListPat :: String -> Q Pat-d10ListPat = strD10ListFail >=> foldr (\x p -> [p| $(d10Pat' x) : $(p) |]) [p| [] |]-------------------------------------------------------- | A single base-10 digit.------ This quasi-quoter, when used as an expression, produces a--- value of type 'D10'.------ >>> d10Nat [d10|5|]--- 5------ >>> d10Nat [d10|a|]--- ...--- ... d10 must be between 0 and 9--- ...------ >>> d10Nat [d10|58|]--- ...--- ... d10 must be a single character--- ...------ This quasi-quoter can also be used as a pattern.------ >>> :{---       case (charD10Maybe '5') of---         Just [d10|4|] -> "A"---         Just [d10|5|] -> "B"---         _             -> "C"--- >>> :}--- "B"------ >>> :{---       case (charD10Maybe '5') of---         Just [d10|x|] -> "A"---         Just [d10|5|] -> "B"---         _             -> "C"--- >>> :}--- ...--- ... d10 must be between 0 and 9--- ...--d10 :: QuasiQuoter-d10 = QuasiQuoter-    { quoteExp  = strD10Fail >=> d10Exp'-    , quotePat  = strD10Fail >=> d10Pat'-    , quoteType = \_ -> fail "d10 cannot be used in a type context"-    , quoteDec  = \_ -> fail "d10 cannot be used in a declaration context"-    }---- | A list of base-10 digits.------ This quasi-quoter, when used as an expression, produces a--- value of type @['D10']@.------ >>> d10Nat <$> [d10list||]--- []------ >>> d10Nat <$> [d10list|5|]--- [5]------ >>> d10Nat <$> [d10list|58|]--- [5,8]------ >>> d10Nat <$> [d10list|a|]--- ...--- ... d10 must be between 0 and 9--- ...------ This quasi-quoter can also be used as a pattern.------ >>> :{---       case [d10list|56|] of---         [d10list|41|] -> "A"---         [d10list|56|] -> "B"---         _             -> "C"--- >>> :}--- "B"------ >>> :{---       case [d10list|56|] of---         [d10list|4x|] -> "A"---         [d10list|56|] -> "B"---         _             -> "C"--- >>> :}--- ...--- ... d10 must be between 0 and 9--- ...--d10list :: QuasiQuoter-d10list = QuasiQuoter-    { quoteExp  = strD10ListFail >=> d10ListExp'-    , quotePat  = d10ListPat-    , quoteType = \_ -> fail "d10list cannot be used in a type context"-    , quoteDec  = \_ -> fail "d10list cannot be used in a declaration context"-    }--------------------------------------------------------- | Addition modulo 10.------ >>> [d10|2|] + [d10|3|]--- [d10|5|]------ >>> [d10|6|] + [d10|7|]--- [d10|3|]--(+) :: D10 -> D10 -> D10-x + y = intMod10 (d10Int x P.+ d10Int y)---- | Subtraction modulo 10.------ >>> [d10|7|] - [d10|5|]--- [d10|2|]------ >>> [d10|3|] - [d10|7|]--- [d10|6|]--(-) :: D10 -> D10 -> D10-x - y = intMod10 (d10Int x P.- d10Int y)---- | Multiplication modulo 10.------ >>> [d10|2|] * [d10|4|]--- [d10|8|]------ >>> [d10|7|] * [d10|8|]--- [d10|6|]--(*) :: D10 -> D10 -> D10-x * y = intMod10 (d10Int x P.* d10Int y)
− src/Data/D10/Num.hs
@@ -1,928 +0,0 @@--- | Defines a 'D10' type as a newtype for any type with an--- instance of the 'Num' class, where the values are restricted--- to numbers between @'fromInteger' 0@ and @'fromInteger' 9@.------ The following modules define @D10@ types in different ways--- but are otherwise very similar to this one:------ * "Data.D10.Char"--- * "Data.D10.Safe"--module Data.D10.Num-    (-    -- * Type-      D10 (..)-    -- $bounded-    -- $enum--    -- * Quasi-quoters-    , d10-    , d10list--    -- * Splice expressions-    , d10Exp-    , d10ListExp--    -- * Splice patterns-    , d10Pat-    , d10ListPat--    -- * Converting between D10 and Char-    , d10Char-    , charD10Maybe-    , charD10Either-    , charD10Fail--    -- * Converting between D10 and String-    , d10Str-    , strD10Maybe-    , strD10Either-    , strD10Fail--    -- * Converting between [D10] and String-    , strD10ListMaybe-    , strD10ListEither-    , strD10ListFail--    -- * Converting between D10 and Natural-    , d10Nat-    , natD10Maybe-    , natD10Either-    , natD10Fail-    , natMod10--    -- * Converting between D10 and Integer-    , d10Integer-    , integerD10Maybe-    , integerD10Either-    , integerD10Fail-    , integerMod10--    -- * Converting between D10 and Int-    , d10Int-    , intD10Maybe-    , intD10Either-    , intD10Fail-    , intMod10--    -- * Converting between D10 and general numeric types-    , d10Num-    , integralD10Maybe-    , integralD10Either-    , integralD10Fail-    , integralMod10--    -- * Modular arithmetic-    , (+), (-), (*)--    ) where--import Data.D10.Predicate---- base-import Control.Monad      ((>=>))-import Control.Monad.Fail (MonadFail (fail))-import Data.Char          (chr, ord)-import Data.Monoid        (Endo (..))-import Numeric.Natural    (Natural)-import Prelude            hiding (fail, (+), (-), (*))--import qualified Prelude as P---- template-haskell-import Language.Haskell.TH.Lib    (litP, integerL)-import Language.Haskell.TH.Quote  (QuasiQuoter (..))-import Language.Haskell.TH.Syntax (Exp (..), Lift, Pat (..), Q)--------------------------------------------------------- | A value of some numeric type @a@ between--- @'fromInteger' 0@ and @'fromInteger' 9@.------ The "Data.D10.Num" module provides many functions for--- constructing 'D10' values, including:------ * @'integerD10Maybe' :: 'Integer' -> 'Maybe' 'D10'@--- * @'integerMod10' :: 'Integer' -> 'D10'@------ There are also several ways to safely write 'D10' literals--- using Template Haskell:------ * With the @QuasiQuotes@ GHC extension enabled, you can write---   use the quasi-quoters 'd10' and 'd10list'.--- * With the @TemplateHaskell@ GHC extension enabled, you can---   splice expressions produced by 'd10Exp' and 'd10ListExp'.--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 (Eq, Ord, Lift)---- $bounded--- ==== Bounded------ >>> minBound :: D10 Integer--- [d10|0|]------ >>> maxBound :: D10 Integer--- [d10|9|]--instance Num a => Bounded (D10 a)-  where-    minBound = D10_Unsafe 0-    maxBound = D10_Unsafe 9---- $enum--- ==== Enum------ >>> [ [d10|5|] .. ]--- [d10list|56789|]------ >>> [ [d10|4|] .. [d10|7|] ]--- [d10list|4567|]------ >>> [ [d10|5|], [d10|4|] .. ]--- [d10list|543210|]------ >>> [ [d10|1|], [d10|3|] .. ]--- [d10list|13579|]------ >>> [ minBound .. maxBound ] :: [D10 Integer]--- [d10list|0123456789|]--instance Integral a => Enum (D10 a)-  where-    fromEnum :: D10 a -> Int-    fromEnum = d10Int--    toEnum :: Int -> D10 a-    toEnum = either error id . intD10Either--    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)--------------------------------------------------------- | Shows base-10 digits using the quasiquoters defined in--- "Data.D10.Char". A single digit is displayed using 'd10'.--- A list of digits is displayed using 'd10list'.--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 = showChar . d10Char--showsStr :: Integral a => [D10 a] -> ShowS-showsStr = appEndo . foldMap (Endo . showsChar)--------------------------------------------------------- | Convert a 'D10' to its underlying 'Char' representation.------ >>> d10Char [d10|7|]--- '7'--d10Char :: Integral a => D10 a -> Char-d10Char (D10_Unsafe x) = chr (ord '0' P.+ fromIntegral x)---- | Convert a 'D10' to a 'String'.------ @'d10Str' x = ['d10Char' x]@------ >>> d10Str [d10|7|]--- "7"--d10Str :: Integral a => D10 a -> String-d10Str x = [d10Char x]---- | Convert a 'D10' to a 'Natural'.------ 'd10Num' is a more general version of this function.------ >>> d10Nat [d10|7|]--- 7--d10Nat :: Integral a => D10 a -> Natural-d10Nat = d10Num---- | Convert a 'D10' to an 'Integer'.------ 'd10Num' is a more general version of this function.------ >>> d10Integer [d10|7|]--- 7--d10Integer :: Integral a => D10 a -> Integer-d10Integer = d10Num---- | Convert a 'D10' to an 'Int'.------ 'd10Num' is a more general version of this function.------ >>> d10Int [d10|7|]--- 7--d10Int :: Integral a => D10 a -> Int-d10Int = d10Num---- | Convert a 'D10' to any kind of number with a 'Num' instance.------ Specialized versions of this function include 'd10Nat',--- 'd10Integer', and 'd10Int'.------ >>> d10Num [d10|7|] :: Integer--- 7--d10Num :: (Integral b, Num a) => D10 b -> a-d10Num (D10_Unsafe x) = fromIntegral x--------------------------------------------------------- | The 'D10' which is uniquely congruent modulo 10 to the given 'Natural'.------ 'integralMod10' is a more general version of this function.------ >>> natMod10 56 :: D10 Int--- [d10|6|]--natMod10 :: Num a => Natural -> D10 a-natMod10 = integralMod10---- | The 'D10' which is uniquely congruent modulo 10 to the given 'Integer'.------ 'integralMod10' is a more general version of this function.------ >>> integerMod10 56 :: D10 Int--- [d10|6|]------ >>> integerMod10 (-56) :: D10 Int--- [d10|4|]--integerMod10 :: Num a => Integer -> D10 a-integerMod10 = integralMod10---- | The 'D10' which is uniquely congruent modulo 10 to the given 'Int'.------ 'integralMod10' is a more general version of this function.------ >>> intMod10 56 :: D10 Int--- [d10|6|]------ >>> intMod10 (-56) :: D10 Int--- [d10|4|]--intMod10 :: Num a => Int -> D10 a-intMod10 = integralMod10---- | The 'D10' which is uniquely congruent modulo 10 to the given number--- (whose type must have an instance of the 'Integral' class).------ Specialized versions of this function include 'natMod10',--- 'integerMod10', and 'intMod10'.------ >>> integralMod10 (56 :: Integer) :: D10 Int--- [d10|6|]------ >>> integralMod10 ((-56) :: Integer) :: D10 Int--- [d10|4|]--integralMod10 :: (Num b, Integral a) => a -> D10 b-integralMod10 x = D10_Unsafe (fromIntegral (x `mod` 10))--------------------------------------------------------- | Convert a 'Char' to a 'D10' if it is within the range--- @'0'@ to @'9'@, or produce 'Nothing' otherwise.------ @'Data.D10.Predicate.isD10Char' x = 'Data.Maybe.isJust' ('charD10Maybe' x)@------ 'charD10Fail' is a more general version of this function.------ >>> charD10Maybe '5'--- Just [d10|5|]------ >>> charD10Maybe 'a'--- Nothing--charD10Maybe :: Num a => Char -> Maybe (D10 a)-charD10Maybe x-        | isD10Char x  =  Just (D10_Unsafe (fromIntegral (ord x P.- ord '0')))-        | otherwise    =  Nothing---- | Convert a 'String' to a 'D10' if it consists of exactly one--- character and that character is within the range @'0'@ to @'9'@,--- or produce 'Nothing' otherwise.------ @'Data.D10.Predicate.isD10Str' x = 'Data.Maybe.isJust' ('strD10Maybe' x)@------ 'strD10Fail' is a more general version of this function.------ >>> strD10Maybe "5"--- Just [d10|5|]------ >>> strD10Maybe "a"--- Nothing------ >>> strD10Maybe "58"--- Nothing--strD10Maybe :: Num a => String -> Maybe (D10 a)-strD10Maybe [x] = charD10Maybe x-strD10Maybe _   = Nothing---- | Convert a 'String' to a list of 'D10' if all of the characters--- in the string are within the range @'0'@ to @'9'@, or produce--- 'Nothing' otherwise.------ @'Data.D10.Predicate.isD10ListStr' x = 'Data.Maybe.isJust' ('strD10ListMaybe' x)@------ 'strD10ListFail' is a more general version of this function.------ >>> strD10ListMaybe "5"--- Just [d10list|5|]------ >>> strD10ListMaybe "a"--- Nothing------ >>> strD10ListMaybe "58"--- Just [d10list|58|]--strD10ListMaybe :: Num a => String -> Maybe [D10 a]-strD10ListMaybe = traverse charD10Maybe---- | Convert a 'Natural' to a 'D10' if it is less than 10,--- or produce 'Nothing' otherwise.------ @'Data.D10.Predicate.isD10Nat' x = 'Data.Maybe.isJust' ('natD10Maybe' x)@------ 'integralD10Maybe', 'natD10Fail', and 'integralD10Fail'--- are more general versions of this function.------ >>> natD10Maybe 5--- Just [d10|5|]------ >>> natD10Maybe 12--- Nothing--natD10Maybe :: Num a => Natural -> Maybe (D10 a)-natD10Maybe x-        | isD10Nat x  =  Just (D10_Unsafe (fromIntegral x))-        | otherwise   =  Nothing---- | Convert an 'Integer' to a 'D10' if it is within the range 0 to 9,--- or produce 'Nothing' otherwise.------ @'Data.D10.Predicate.isD10Integer' x = 'Data.Maybe.isJust' ('integerD10Maybe' x)@------ 'integralD10Maybe', 'integerD10Fail', and 'integralD10Fail'--- are more general versions of this function.------ >>> integerD10Maybe 5--- Just [d10|5|]------ >>> integerD10Maybe 12--- Nothing------ >>> integerD10Maybe (-5)--- Nothing--integerD10Maybe :: Num a => Integer -> Maybe (D10 a)-integerD10Maybe x-        | isD10Integer x  =  Just (D10_Unsafe (fromIntegral x))-        | otherwise       =  Nothing---- | Convert an 'Int' to a 'D10' if it is within the range 0 to 9,--- or produce 'Nothing' otherwise.------ @'Data.D10.Predicate.isD10Int' x = 'Data.Maybe.isJust' ('intD10Maybe' x)@------ 'integralD10Maybe', 'intD10Fail', and 'integralD10Fail'--- are more general versions of this function.------ >>> intD10Maybe 5--- Just [d10|5|]------ >>> intD10Maybe 12--- Nothing------ >>> intD10Maybe (-5)--- Nothing--intD10Maybe :: Num a => Int -> Maybe (D10 a)-intD10Maybe x-        | isD10Int x  =  Just (D10_Unsafe (fromIntegral x))-        | otherwise   =  Nothing---- | Construct a 'D10' from any kind of number with an 'Integral'--- instance, or produce 'Nothing' if the number falls outside the--- range 0 to 9.------ @'Data.D10.Predicate.isD10Integral' x = 'Data.Maybe.isJust' ('integralD10Maybe' x)@------ Specialized versions of this function include 'natD10Maybe',--- 'integerD10Maybe', and 'intD10Maybe'.------ 'integralD10Fail' is a more general version of this function.------ >>> integralD10Maybe (5 :: Integer)--- Just [d10|5|]------ >>> integralD10Maybe (12 :: Integer)--- Nothing------ >>> integralD10Maybe ((-5) :: Integer)--- Nothing--integralD10Maybe :: (Num b, Integral a) => a -> Maybe (D10 b)-integralD10Maybe x = integerD10Maybe (toInteger x)--------------------------------------------------------- | Convert a 'Char' to a 'D10' if it is within the range--- @'0'@ to @'9'@, or 'Left' with an error message otherwise.------ >>> charD10Either '5'--- Right [d10|5|]------ >>> charD10Either 'a'--- Left "d10 must be between 0 and 9"--charD10Either :: Num a => Char -> Either String (D10 a)-charD10Either x-        | isD10Char x  =  Right (D10_Unsafe (fromIntegral (ord x P.- ord '0')))-        | otherwise    =  Left "d10 must be between 0 and 9"---- | Convert a 'String' to a 'D10' if it consists of a single--- character and that character is within the range @'0'@ to--- @'9'@, or 'Left' with an error message otherwise.------ >>> strD10Either "5"--- Right [d10|5|]------ >>> strD10Either "a"--- Left "d10 must be between 0 and 9"------ >>> strD10Either "58"--- Left "d10 must be a single character"--strD10Either :: Num a => String -> Either String (D10 a)-strD10Either [x]         =  charD10Either x-strD10Either _           =  Left "d10 must be a single character"---- | Convert a 'String' to a 'D10' if all of the characters in--- the string fall within the range @'0'@ to @'9'@, or 'Left'--- with an error message otherwise.------ >>> strD10ListEither "5"--- Right [d10list|5|]------ >>> strD10ListEither "a"--- Left "d10 must be between 0 and 9"------ >>> strD10ListEither "58"--- Right [d10list|58|]--strD10ListEither :: Num a => String -> Either String [D10 a]-strD10ListEither = traverse charD10Either---- | Convert a 'Natural' to a 'D10' if it is less than 10,--- or 'Left' with an error message otherwise.------ >>> natD10Either 5--- Right [d10|5|]------ >>> natD10Either 12--- Left "d10 must be less than 10"--natD10Either :: Num a => Natural -> Either String (D10 a)-natD10Either x =-    case (natD10Maybe x) of-        Just y  -> Right y-        Nothing -> Left "d10 must be less than 10"---- | Convert an 'Integer' to a 'D10' if it is within the--- range 0 to 9, or 'Left' with an error message otherwise.------ >>> integerD10Either 5--- Right [d10|5|]------ >>> integerD10Either 12--- Left "d10 must be between 0 and 9"------ >>> integerD10Either (-5)--- Left "d10 must be between 0 and 9"--integerD10Either :: Num a => Integer -> Either String (D10 a)-integerD10Either x =-    case (integerD10Maybe x) of-        Just y  -> Right y-        Nothing -> Left "d10 must be between 0 and 9"---- | Convert an 'Int' to a 'D10' if it is within the range--- 0 to 9, or 'Left' with an error message otherwise.------ >>> intD10Either 5--- Right [d10|5|]------ >>> intD10Either 12--- Left "d10 must be between 0 and 9"------ >>> intD10Either (-5)--- Left "d10 must be between 0 and 9"--intD10Either :: Num a => Int -> Either String (D10 a)-intD10Either x =-    case (intD10Maybe x) of-        Just y  ->  Right y-        Nothing ->  Left "d10 must be between 0 and 9"---- | Convert a number of a type that has an 'Integral' instance--- to a 'D10' if it falls within the range 0 to 9, or 'Left'--- with an error message otherwise.------ >>> integralD10Either (5 :: Integer)--- Right [d10|5|]------ >>> integralD10Either (12 :: Integer)--- Left "d10 must be between 0 and 9"------ >>> integralD10Either ((-5) :: Integer)--- Left "d10 must be between 0 and 9"--integralD10Either :: (Num b, Integral a) => a -> Either String (D10 b)-integralD10Either x = integerD10Either (toInteger x)--------------------------------------------------------- | Convert a 'Char' to a 'D10' if it is within the range--- @'0'@ to @'9'@, or 'fail' with an error message otherwise.------ 'charD10Maybe' is a specialized version of this function.------ >>> charD10Fail '5' :: IO (D10 Int)--- [d10|5|]------ >>> charD10Fail 'a' :: IO (D10 Int)--- *** Exception: user error (d10 must be between 0 and 9)--charD10Fail :: (Num a, MonadFail m) => Char -> m (D10 a)-charD10Fail x-        | isD10Char x  =  return (D10_Unsafe (fromIntegral (ord x P.- ord '0')))-        | otherwise    =  fail "d10 must be between 0 and 9"---- | Convert a 'String' to a 'D10' if it consists of a single--- character and that character is within the range @'0'@ to--- @'9'@, or 'fail' with an error message otherwise.------ 'strD10Maybe' is a specialized version of this function.------ >>> strD10Fail "5" :: IO (D10 Int)--- [d10|5|]------ >>> strD10Fail "a" :: IO (D10 Int)--- *** Exception: user error (d10 must be between 0 and 9)------ >>> strD10Fail "58" :: IO (D10 Int)--- *** Exception: user error (d10 must be a single character)--strD10Fail :: (Num a, MonadFail m) => String -> m (D10 a)-strD10Fail [x]         =  charD10Fail x-strD10Fail _           =  fail "d10 must be a single character"---- | Convert a 'String' to a 'D10' if all of the characters in--- the string fall within the range @'0'@ to @'9'@, or 'fail'--- with an error message otherwise.------ 'strD10ListMaybe' is a specialized version of this function.------ >>> strD10ListFail "5" :: IO [D10 Int]--- [d10list|5|]------ >>> strD10ListFail "a" :: IO [D10 Int]--- *** Exception: user error (d10 must be between 0 and 9)------ >>> strD10ListFail "58" :: IO [D10 Int]--- [d10list|58|]--strD10ListFail :: (Num a, MonadFail m) => String -> m [D10 a]-strD10ListFail = traverse charD10Fail---- | Convert a 'Natural' to a 'D10' if it is less than 10,--- or 'fail' with an error message otherwise.------ 'natD10Maybe' is a specialized version of this function.------ 'integralD10Fail' is a more general version of this function.------ >>> natD10Fail 5 :: IO (D10 Int)--- [d10|5|]------ >>> natD10Fail 12 :: IO (D10 Int)--- *** Exception: user error (d10 must be less than 10)--natD10Fail :: (Num a, MonadFail m) => Natural -> m (D10 a)-natD10Fail x =-    case (natD10Maybe x) of-        Just y  -> return y-        Nothing -> fail "d10 must be less than 10"---- | Convert an 'Integer' to a 'D10' if it is within the--- range 0 to 9, or 'fail' with an error message otherwise.------ 'integerD10Maybe' is a specialized version of this function.------ 'integralD10Fail' is a more general version of this function.------ >>> integerD10Fail 5 :: IO (D10 Int)--- [d10|5|]------ >>> integerD10Fail 12 :: IO (D10 Int)--- *** Exception: user error (d10 must be between 0 and 9)------ >>> integerD10Fail (-5) :: IO (D10 Int)--- *** Exception: user error (d10 must be between 0 and 9)--integerD10Fail :: (Num a, MonadFail m) => Integer -> m (D10 a)-integerD10Fail x =-    case (integerD10Maybe x) of-        Just y  -> return y-        Nothing -> fail "d10 must be between 0 and 9"---- | Convert an 'Int' to a 'D10' if it is within the range--- 0 to 9, or 'fail' with an error message otherwise.------ 'intD10Maybe' is a specialized version of this function.------ 'integralD10Fail' is a more general version of this function.------ >>> intD10Fail 5 :: IO (D10 Int)--- [d10|5|]------ >>> intD10Fail 12 :: IO (D10 Int)--- *** Exception: user error (d10 must be between 0 and 9)------ >>> intD10Fail (-5) :: IO (D10 Int)--- *** Exception: user error (d10 must be between 0 and 9)--intD10Fail :: (Num a, MonadFail m) => Int -> m (D10 a)-intD10Fail x =-    case (intD10Maybe x) of-        Just y  ->  return y-        Nothing ->  fail "d10 must be between 0 and 9"---- | Convert a number of a type that has an 'Integral' instance--- to a 'D10' if it falls within the range 0 to 9, or 'fail'--- with an error message otherwise.------ 'natD10Maybe', 'integerD10Maybe', 'intD10Maybe',--- 'integralD10Maybe', 'natD10Fail', 'integerD10Fail', and--- 'intD10Fail' are all specialized versions of this function.------ >>> integralD10Fail (5 :: Integer) :: IO (D10 Int)--- [d10|5|]------ >>> integralD10Fail (12 :: Integer) :: IO (D10 Int)--- *** Exception: user error (d10 must be between 0 and 9)------ >>> integralD10Fail ((-5) :: Integer) :: IO (D10 Int)--- *** Exception: user error (d10 must be between 0 and 9)--integralD10Fail :: (Num b, Integral a, MonadFail m) => a -> m (D10 b)-integralD10Fail x = integerD10Fail (toInteger x)--------------------------------------------------------- | Produces an expression of type @'D10' a@ that can be used--- in a Template Haskell splice.------ >>> d10Nat $(d10Exp 5)--- 5------ >>> d10Nat $(d10Exp 12)--- ...--- ... d10 must be between 0 and 9--- ...------ You may also be interested in 'd10', a quasi-quoter which--- does something similar.--d10Exp :: Integer -> Q Exp-d10Exp = integerD10Fail >=> d10Exp'--d10Exp' :: D10 Integer -> Q Exp-d10Exp' (D10_Unsafe x) = [| D10_Unsafe (fromInteger x) |]---- | Produces an expression of type @['D10' a]@ that can be used--- in a Template Haskell splice.------ >>> d10Nat <$> $(d10ListExp "")--- []------ >>> d10Nat <$> $(d10ListExp "5")--- [5]------ >>> d10Nat <$> $(d10ListExp "58")--- [5,8]------ >>> d10Nat <$> $(d10ListExp "a")--- ...--- ... d10 must be between 0 and 9--- ...------ You may also be interested in 'd10list', a quasi-quoter which--- does something similar.--d10ListExp :: String -> Q Exp-d10ListExp = strD10ListFail >=> d10ListExp'--d10ListExp' :: [D10 Integer] -> Q Exp-d10ListExp' xs = [| xs |]--------------------------------------------------------- | Produces a pattern that can be used in a splice--- to match a particular @'D10' a@ value.------ >>> :{---       case (charD10Maybe '5') of---         Just $(d10Pat 4) -> "A"---         Just $(d10Pat 5) -> "B"---         _                -> "C"--- >>> :}--- "B"------ You may wish to use the 'd10' quasi-quoter instead.--d10Pat :: Integer -> Q Pat-d10Pat = integerD10Fail >=> d10Pat'--d10Pat' :: D10 Integer -> Q Pat-d10Pat' (D10_Unsafe x) = [p| D10_Unsafe $(litP $ integerL x) |]--d10Pat'' :: Integral a => D10 a -> Q Pat-d10Pat'' (D10_Unsafe x) = [p| D10_Unsafe $(litP $ integerL $ toInteger x) |]---- | Produces a pattern that can be used in a splice--- to match a particular list of @'D10' a@ values.------ >>> :{---       case (strD10ListMaybe "56") of---         Just $(d10ListPat "42") -> "A"---         Just $(d10ListPat "56") -> "B"---         _                       -> "C"--- >>> :}--- "B"------ You may wish to use the 'd10list' quasi-quoter instead.--d10ListPat :: String -> Q Pat-d10ListPat = strD10ListFail >=> d10ListPat'--d10ListPat' :: [D10 Integer] -> Q Pat-d10ListPat' = foldr (\x p -> [p| $(d10Pat'' x) : $(p) |]) [p| [] |]--------------------------------------------------------- | A single base-10 digit.------ This quasi-quoter, when used as an expression, produces a--- value of type @'D10' a@.------ >>> d10Nat [d10|5|]--- 5------ >>> d10Nat [d10|a|]--- ...--- ... d10 must be between 0 and 9--- ...------ >>> d10Nat [d10|58|]--- ...--- ... d10 must be a single character--- ...------ This quasi-quoter can also be used as a pattern.------ >>> :{---       case (charD10Maybe '5') of---         Just [d10|4|] -> "A"---         Just [d10|5|] -> "B"---         _             -> "C"--- >>> :}--- "B"------ >>> :{---       case (charD10Maybe '5') of---         Just [d10|x|] -> "A"---         Just [d10|5|] -> "B"---         _             -> "C"--- >>> :}--- ...--- ... d10 must be between 0 and 9--- ...--d10 :: QuasiQuoter-d10 = QuasiQuoter-    { quoteExp  = strD10Fail >=> d10Exp'-    , quotePat  = strD10Fail >=> d10Pat'-    , quoteType = \_ -> fail "d10 cannot be used in a type context"-    , quoteDec  = \_ -> fail "d10 cannot be used in a declaration context"-    }---- | A list of base-10 digits.------ This quasi-quoter, when used as an expression, produces a--- value of type @['D10' a]@.------ >>> d10Nat <$> [d10list||]--- []------ >>> d10Nat <$> [d10list|5|]--- [5]------ >>> d10Nat <$> [d10list|58|]--- [5,8]------ >>> d10Nat <$> [d10list|a|]--- ...--- ... d10 must be between 0 and 9--- ...------ This quasi-quoter can also be used as a pattern.------ >>> :{---       case [d10list|56|] of---         [d10list|41|] -> "A"---         [d10list|56|] -> "B"---         _             -> "C"--- >>> :}--- "B"------ >>> :{---       case [d10list|56|] of---         [d10list|4x|] -> "A"---         [d10list|56|] -> "B"---         _             -> "C"--- >>> :}--- ...--- ... d10 must be between 0 and 9--- ...--d10list :: QuasiQuoter-d10list = QuasiQuoter-    { quoteExp  = strD10ListFail >=> d10ListExp'-    , quotePat  = strD10ListFail >=> d10ListPat'-    , quoteType = \_ -> fail "d10list cannot be used in a type context"-    , quoteDec  = \_ -> fail "d10list cannot be used in a declaration context"-    }--------------------------------------------------------- | Addition modulo 10.------ >>> [d10|2|] + [d10|3|]--- [d10|5|]------ >>> [d10|6|] + [d10|7|]--- [d10|3|]--(+) :: Integral a => D10 a -> D10 a -> D10 a-x + y = intMod10 (d10Int x P.+ d10Int y)---- | Subtraction modulo 10.------ >>> [d10|7|] - [d10|5|]--- [d10|2|]------ >>> [d10|3|] - [d10|7|]--- [d10|6|]--(-) :: Integral a => D10 a -> D10 a -> D10 a-x - y = intMod10 (d10Int x P.- d10Int y)---- | Multiplication modulo 10.------ >>> [d10|2|] * [d10|4|]--- [d10|8|]------ >>> [d10|7|] * [d10|8|]--- [d10|6|]--(*) :: Integral a => D10 a -> D10 a -> D10 a-x * y = intMod10 (d10Int x P.* d10Int y)
− src/Data/D10/Predicate.hs
@@ -1,37 +0,0 @@--- | Functions to test whether values of various--- types represent digits in the range /0/ to /9/.-module Data.D10.Predicate where--import Numeric.Natural (Natural)---- | Determines whether a 'Char' is in the range @'0'@ to @'9'@.-isD10Char :: Char -> Bool-isD10Char x = x >= '0' && x <= '9'---- | Determines whether a 'String' consists of a single character--- and that character is within the range @'0'@ to @'9'@.-isD10Str :: String -> Bool-isD10Str [x] = isD10Char x-isD10Str _   = False---- | Determines whether a 'String' consists entirely of characters--- that are within the range @'0'@ to @'9'@.-isD10ListStr :: String -> Bool-isD10ListStr = all isD10Char---- | Determines whether a 'Natural' is in the range 0 to 9.-isD10Nat :: Natural -> Bool-isD10Nat x = x <= 9---- | Determines whether an 'Integer' is in the range 0 to 9.-isD10Integer :: Integer -> Bool-isD10Integer x = x >= 0 && x <= 9---- | Determines whether an 'Int' is in the range 0 to 9.-isD10Int :: Int -> Bool-isD10Int x = x >= 0 && x <= 9---- | Determines whether a number whose type has an 'Integral'--- instance is in the range 0 to 9.-isD10Integral :: Integral a => a -> Bool-isD10Integral x = isD10Integer (toInteger x)
− src/Data/D10/Safe.hs
@@ -1,876 +0,0 @@--- | Defines a 'D10' type as--- @'D0' | 'D1' | 'D2' | 'D3' | 'D4' | 'D5' | 'D6' | 'D7' | 'D8' | 'D9'@.------ The following modules define @D10@ types in different ways--- but are otherwise very similar to this one:------ * "Data.D10.Char"--- * "Data.D10.Num"------ This module is called "safe" because, in contrast with the--- alternative representations of a digit defined in the other--- modules, this 'D10' type does not include any possibility--- of representing an invalid non-digit value.--module Data.D10.Safe-    (-    -- * Type-      D10 (..)-    -- $bounded-    -- $enum--    -- * Quasi-quoters-    , d10list--    -- * Splice expressions-    , d10ListExp--    -- * Splice patterns-    , d10ListPat--    -- * Converting between D10 and Char-    , d10Char-    , charD10Maybe-    , charD10Either-    , charD10Fail--    -- * Converting between D10 and String-    , d10Str-    , strD10Maybe-    , strD10Either-    , strD10Fail--    -- * Converting between [D10] and String-    , strD10ListMaybe-    , strD10ListEither-    , strD10ListFail--    -- * Converting between D10 and Natural-    , d10Nat-    , natD10Maybe-    , natD10Either-    , natD10Fail-    , natMod10--    -- * Converting between D10 and Integer-    , d10Integer-    , integerD10Maybe-    , integerD10Either-    , integerD10Fail-    , integerMod10--    -- * Converting between D10 and Int-    , d10Int-    , intD10Maybe-    , intD10Either-    , intD10Fail-    , intMod10--    -- * Converting between D10 and general numeric types-    , d10Num-    , integralD10Maybe-    , integralD10Either-    , integralD10Fail-    , integralMod10--    -- * Modular arithmetic-    , (+), (-), (*)--    ) where---- base-import Control.Monad      ((>=>))-import Control.Monad.Fail (MonadFail (fail))-import Data.Data          (Data)-import GHC.Generics       (Generic)-import Numeric.Natural    (Natural)-import Prelude            hiding (fail, (+), (-), (*))--import qualified Prelude as P---- template-haskell-import Language.Haskell.TH.Quote  (QuasiQuoter (..))-import Language.Haskell.TH.Syntax (Exp (..), Lift, Pat (..), Q, dataToPatQ)--------------------------------------------------------- | A whole number between /0/ and /9/.--data D10-    = D0  -- ^ Zero-    | D1  -- ^ One-    | D2  -- ^ Two-    | D3  -- ^ Three-    | D4  -- ^ Four-    | D5  -- ^ Five-    | D6  -- ^ Six-    | D7  -- ^ Seven-    | D8  -- ^ Eight-    | D9  -- ^ Nine-    deriving (Bounded, Enum, Eq, Lift, Ord, Show, Data, Generic)---- $bounded--- ==== Bounded------ >>> minBound :: D10--- D0------ >>> maxBound :: D10--- D9---- $enum--- ==== Enum------ >>> [ D5 .. ]--- [D5,D6,D7,D8,D9]------ >>> [ D4 .. D7 ]--- [D4,D5,D6,D7]------ >>> [ D5, D4 .. ]--- [D5,D4,D3,D2,D1,D0]------ >>> [ D1, D3 .. ]--- [D1,D3,D5,D7,D9]------ >>> [ minBound .. maxBound ] :: [D10]--- [D0,D1,D2,D3,D4,D5,D6,D7,D8,D9]--------------------------------------------------------- | Convert a 'D10' to its underlying 'Char' representation.------ >>> d10Char D7--- '7'--d10Char :: D10 -> Char-d10Char x =-    case x of-        D0 -> '0'-        D1 -> '1'-        D2 -> '2'-        D3 -> '3'-        D4 -> '4'-        D5 -> '5'-        D6 -> '6'-        D7 -> '7'-        D8 -> '8'-        D9 -> '9'---- | Convert a 'D10' to a 'String'.------ @'d10Str' x = ['d10Char' x]@------ >>> d10Str D7--- "7"--d10Str :: D10 -> String-d10Str x = [d10Char x]---- | Convert a 'D10' to a 'Natural'.------ 'd10Num' is a more general version of this function.------ >>> d10Nat D7--- 7--d10Nat :: D10 -> Natural-d10Nat = d10Num---- | Convert a 'D10' to an 'Integer'.------ 'd10Num' is a more general version of this function.------ >>> d10Integer D7--- 7--d10Integer :: D10 -> Integer-d10Integer = d10Num---- | Convert a 'D10' to an 'Int'.------ 'd10Num' is a more general version of this function.------ >>> d10Int D7--- 7--d10Int :: D10 -> Int-d10Int = d10Num---- | Convert a 'D10' to any kind of number with a 'Num' instance.------ Specialized versions of this function include 'd10Nat',--- 'd10Integer', and 'd10Int'.------ >>> d10Num D7 :: Integer--- 7--d10Num :: Num a => D10 -> a-d10Num x =-    case x of-        D0 -> 0-        D1 -> 1-        D2 -> 2-        D3 -> 3-        D4 -> 4-        D5 -> 5-        D6 -> 6-        D7 -> 7-        D8 -> 8-        D9 -> 9--------------------------------------------------------- | The 'D10' which is uniquely congruent modulo 10 to the given 'Natural'.------ 'integralMod10' is a more general version of this function.------ >>> natMod10 56--- D6--natMod10 :: Natural -> D10-natMod10 = integralMod10---- | The 'D10' which is uniquely congruent modulo 10 to the given 'Integer'.------ 'integralMod10' is a more general version of this function.------ >>> integerMod10 56--- D6------ >>> integerMod10 (-56)--- D4--integerMod10 :: Integer -> D10-integerMod10 = integralMod10---- | The 'D10' which is uniquely congruent modulo 10 to the given 'Int'.------ 'integralMod10' is a more general version of this function.------ >>> intMod10 56--- D6------ >>> intMod10 (-56)--- D4--intMod10 :: Int -> D10-intMod10 = integralMod10---- | The 'D10' which is uniquely congruent modulo 10 to the given number--- (whose type must have an instance of the 'Integral' class).------ Specialized versions of this function include 'natMod10',--- 'integerMod10', and 'intMod10'.------ >>> integralMod10 (56 :: Integer)--- D6------ >>> integralMod10 ((-56) :: Integer)--- D4--integralMod10 :: Integral a => a -> D10-integralMod10 x =-    case (x `mod` 10) of-        0 -> D0-        1 -> D1-        2 -> D2-        3 -> D3-        4 -> D4-        5 -> D5-        6 -> D6-        7 -> D7-        8 -> D8-        9 -> D9-        _ -> error "x `mod` 10 is not between 0 and 9"--------------------------------------------------------- | Convert a 'Char' to a 'D10' if it is within the range--- @'0'@ to @'9'@, or produce 'Nothing' otherwise.------ @'Data.D10.Predicate.isD10Char' x = 'Data.Maybe.isJust' ('charD10Maybe' x)@------ 'charD10Fail' is a more general version of this function.------ >>> charD10Maybe '5'--- Just D5------ >>> charD10Maybe 'a'--- Nothing--charD10Maybe :: Char -> Maybe D10-charD10Maybe x =-    case x of-        '0' -> Just D0-        '1' -> Just D1-        '2' -> Just D2-        '3' -> Just D3-        '4' -> Just D4-        '5' -> Just D5-        '6' -> Just D6-        '7' -> Just D7-        '8' -> Just D8-        '9' -> Just D9-        _   -> Nothing---- | Convert a 'String' to a 'D10' if it consists of exactly one--- character and that character is within the range @'0'@ to @'9'@,--- or produce 'Nothing' otherwise.------ @'Data.D10.Predicate.isD10Str' x = 'Data.Maybe.isJust' ('strD10Maybe' x)@------ 'strD10Fail' is a more general version of this function.------ >>> strD10Maybe "5"--- Just D5------ >>> strD10Maybe "a"--- Nothing------ >>> strD10Maybe "58"--- Nothing--strD10Maybe :: String -> Maybe D10-strD10Maybe [x] = charD10Maybe x-strD10Maybe _   = Nothing---- | Convert a 'String' to a list of 'D10' if all of the characters--- in the string are within the range @'0'@ to @'9'@, or produce--- 'Nothing' otherwise.------ @'Data.D10.Predicate.isD10ListStr' x = 'Data.Maybe.isJust' ('strD10ListMaybe' x)@------ 'strD10ListFail' is a more general version of this function.------ >>> strD10ListMaybe "5"--- Just [D5]------ >>> strD10ListMaybe "a"--- Nothing------ >>> strD10ListMaybe "58"--- Just [D5,D8]--strD10ListMaybe :: String -> Maybe [D10]-strD10ListMaybe = traverse charD10Maybe---- | Convert a 'Natural' to a 'D10' if it is less than 10,--- or produce 'Nothing' otherwise.------ @'Data.D10.Predicate.isD10Nat' x = 'Data.Maybe.isJust' ('natD10Maybe' x)@------ 'integralD10Maybe', 'natD10Fail', and 'integralD10Fail'--- are more general versions of this function.------ >>> natD10Maybe 5--- Just D5------ >>> natD10Maybe 12--- Nothing--natD10Maybe :: Natural -> Maybe D10-natD10Maybe = integralD10Maybe---- | Convert an 'Integer' to a 'D10' if it is within the range 0 to 9,--- or produce 'Nothing' otherwise.------ @'Data.D10.Predicate.isD10Integer' x = 'Data.Maybe.isJust' ('integerD10Maybe' x)@------ 'integralD10Maybe', 'integerD10Fail', and 'integralD10Fail'--- are more general versions of this function.------ >>> integerD10Maybe 5--- Just D5------ >>> integerD10Maybe 12--- Nothing------ >>> integerD10Maybe (-5)--- Nothing--integerD10Maybe :: Integer -> Maybe D10-integerD10Maybe = integralD10Maybe---- | Convert an 'Int' to a 'D10' if it is within the range 0 to 9,--- or produce 'Nothing' otherwise.------ @'Data.D10.Predicate.isD10Int' x = 'Data.Maybe.isJust' ('intD10Maybe' x)@------ 'integralD10Maybe', 'intD10Fail', and 'integralD10Fail'--- are more general versions of this function.------ >>> intD10Maybe 5--- Just D5------ >>> intD10Maybe 12--- Nothing------ >>> intD10Maybe (-5)--- Nothing--intD10Maybe :: Int -> Maybe D10-intD10Maybe = integralD10Maybe---- | Construct a 'D10' from any kind of number with an 'Integral'--- instance, or produce 'Nothing' if the number falls outside the--- range 0 to 9.------ @'Data.D10.Predicate.isD10Integral' x = 'Data.Maybe.isJust' ('integralD10Maybe' x)@------ Specialized versions of this function include 'natD10Maybe',--- 'integerD10Maybe', and 'intD10Maybe'.------ 'integralD10Fail' is a more general version of this function.------ >>> integralD10Maybe (5 :: Integer)--- Just D5------ >>> integralD10Maybe (12 :: Integer)--- Nothing------ >>> integralD10Maybe ((-5) :: Integer)--- Nothing--integralD10Maybe :: Integral a => a -> Maybe D10-integralD10Maybe x =-    case x of-        0 -> Just D0-        1 -> Just D1-        2 -> Just D2-        3 -> Just D3-        4 -> Just D4-        5 -> Just D5-        6 -> Just D6-        7 -> Just D7-        8 -> Just D8-        9 -> Just D9-        _ -> Nothing--------------------------------------------------------- | Convert a 'Char' to a 'D10' if it is within the range--- @'0'@ to @'9'@, or 'Left' with an error message otherwise.------ >>> charD10Either '5'--- Right D5------ >>> charD10Either 'a'--- Left "d10 must be between 0 and 9"--charD10Either :: Char -> Either String D10-charD10Either x =-    case x of-        '0' -> Right D0-        '1' -> Right D1-        '2' -> Right D2-        '3' -> Right D3-        '4' -> Right D4-        '5' -> Right D5-        '6' -> Right D6-        '7' -> Right D7-        '8' -> Right D8-        '9' -> Right D9-        _   -> Left "d10 must be between 0 and 9"---- | Convert a 'String' to a 'D10' if it consists of a single--- character and that character is within the range @'0'@ to--- @'9'@, or 'Left' with an error message otherwise.------ >>> strD10Either "5"--- Right D5------ >>> strD10Either "a"--- Left "d10 must be between 0 and 9"------ >>> strD10Either "58"--- Left "d10 must be a single character"--strD10Either :: String -> Either String D10-strD10Either [x] = charD10Either x-strD10Either _   = Left "d10 must be a single character"---- | Convert a 'String' to a 'D10' if all of the characters in--- the string fall within the range @'0'@ to @'9'@, or 'Left'--- with an error message otherwise.------ >>> strD10ListEither "5"--- Right [D5]------ >>> strD10ListEither "a"--- Left "d10 must be between 0 and 9"------ >>> strD10ListEither "58"--- Right [D5,D8]--strD10ListEither :: String -> Either String [D10]-strD10ListEither = traverse charD10Either---- | Convert a 'Natural' to a 'D10' if it is less than 10,--- or 'Left' with an error message otherwise.------ >>> natD10Either 5--- Right D5------ >>> natD10Either 12--- Left "d10 must be less than 10"--natD10Either :: Natural -> Either String D10-natD10Either x =-    case x of-        0 -> Right D0-        1 -> Right D1-        2 -> Right D2-        3 -> Right D3-        4 -> Right D4-        5 -> Right D5-        6 -> Right D6-        7 -> Right D7-        8 -> Right D8-        9 -> Right D9-        _ -> Left "d10 must be less than 10"---- | Convert an 'Integer' to a 'D10' if it is within the--- range 0 to 9, or 'Left' with an error message otherwise.------ >>> integerD10Either 5--- Right D5------ >>> integerD10Either 12--- Left "d10 must be between 0 and 9"------ >>> integerD10Either (-5)--- Left "d10 must be between 0 and 9"--integerD10Either :: Integer -> Either String D10-integerD10Either = integralD10Either---- | Convert an 'Int' to a 'D10' if it is within the range--- 0 to 9, or 'Left' with an error message otherwise.------ >>> intD10Either 5--- Right D5------ >>> intD10Either 12--- Left "d10 must be between 0 and 9"------ >>> intD10Either (-5)--- Left "d10 must be between 0 and 9"--intD10Either :: Int -> Either String D10-intD10Either = integralD10Either---- | Convert a number of a type that has an 'Integral' instance--- to a 'D10' if it falls within the range 0 to 9, or 'Left'--- with an error message otherwise.------ >>> integralD10Either (5 :: Integer)--- Right D5------ >>> integralD10Either (12 :: Integer)--- Left "d10 must be between 0 and 9"------ >>> integralD10Either ((-5) :: Integer)--- Left "d10 must be between 0 and 9"--integralD10Either :: Integral a => a -> Either String D10-integralD10Either x =-    case (integralD10Maybe x) of-        Just y  -> Right y-        Nothing -> Left "d10 must be between 0 and 9"--------------------------------------------------------- | Convert a 'Char' to a 'D10' if it is within the range--- @'0'@ to @'9'@, or 'fail' with an error message otherwise.------ 'charD10Maybe' is a specialized version of this function.------ >>> charD10Fail '5' :: IO D10--- D5------ >>> charD10Fail 'a' :: IO D10--- *** Exception: user error (d10 must be between 0 and 9)--charD10Fail :: MonadFail m => Char -> m D10-charD10Fail x =-    case x of-        '0' -> return D0-        '1' -> return D1-        '2' -> return D2-        '3' -> return D3-        '4' -> return D4-        '5' -> return D5-        '6' -> return D6-        '7' -> return D7-        '8' -> return D8-        '9' -> return D9-        _   -> fail "d10 must be between 0 and 9"---- | Convert a 'String' to a 'D10' if it consists of a single--- character and that character is within the range @'0'@ to--- @'9'@, or 'fail' with an error message otherwise.------ 'strD10Maybe' is a specialized version of this function.------ >>> strD10Fail "5" :: IO D10--- D5------ >>> strD10Fail "a" :: IO D10--- *** Exception: user error (d10 must be between 0 and 9)------ >>> strD10Fail "58" :: IO D10--- *** Exception: user error (d10 must be a single character)--strD10Fail :: MonadFail m => String -> m D10-strD10Fail [x] = charD10Fail x-strD10Fail _   = fail "d10 must be a single character"---- | Convert a 'String' to a 'D10' if all of the characters in--- the string fall within the range @'0'@ to @'9'@, or 'fail'--- with an error message otherwise.------ 'strD10ListMaybe' is a specialized version of this function.------ >>> strD10ListFail "5" :: IO [D10]--- [D5]------ >>> strD10ListFail "a" :: IO [D10]--- *** Exception: user error (d10 must be between 0 and 9)------ >>> strD10ListFail "58" :: IO [D10]--- [D5,D8]--strD10ListFail :: MonadFail m => String -> m [D10]-strD10ListFail = traverse charD10Fail---- | Convert a 'Natural' to a 'D10' if it is less than 10,--- or 'fail' with an error message otherwise.------ 'natD10Maybe' is a specialized version of this function.------ 'integralD10Fail' is a more general version of this function.------ >>> natD10Fail 5 :: IO D10--- D5------ >>> natD10Fail 12 :: IO D10--- *** Exception: user error (d10 must be less than 10)--natD10Fail :: MonadFail m => Natural -> m D10-natD10Fail x =-    case x of-        0 -> return D0-        1 -> return D1-        2 -> return D2-        3 -> return D3-        4 -> return D4-        5 -> return D5-        6 -> return D6-        7 -> return D7-        8 -> return D8-        9 -> return D9-        _ -> fail "d10 must be less than 10"---- | Convert an 'Integer' to a 'D10' if it is within the--- range 0 to 9, or 'fail' with an error message otherwise.------ 'integerD10Maybe' is a specialized version of this function.------ 'integralD10Fail' is a more general version of this function.------ >>> integerD10Fail 5 :: IO D10--- D5------ >>> integerD10Fail 12 :: IO D10--- *** Exception: user error (d10 must be between 0 and 9)------ >>> integerD10Fail (-5) :: IO D10--- *** Exception: user error (d10 must be between 0 and 9)--integerD10Fail :: MonadFail m => Integer -> m D10-integerD10Fail = integralD10Fail---- | Convert an 'Int' to a 'D10' if it is within the range--- 0 to 9, or 'fail' with an error message otherwise.------ 'intD10Maybe' is a specialized version of this function.------ 'integralD10Fail' is a more general version of this function.------ >>> intD10Fail 5 :: IO D10--- D5------ >>> intD10Fail 12 :: IO D10--- *** Exception: user error (d10 must be between 0 and 9)------ >>> intD10Fail (-5) :: IO D10--- *** Exception: user error (d10 must be between 0 and 9)--intD10Fail :: MonadFail m => Int -> m D10-intD10Fail = integralD10Fail---- | Convert a number of a type that has an 'Integral' instance--- to a 'D10' if it falls within the range 0 to 9, or 'fail'--- with an error message otherwise.------ 'natD10Maybe', 'integerD10Maybe', 'intD10Maybe',--- 'integralD10Maybe', 'natD10Fail', 'integerD10Fail', and--- 'intD10Fail' are all specialized versions of this function.------ >>> integralD10Fail (5 :: Integer) :: IO D10--- D5------ >>> integralD10Fail (12 :: Integer) :: IO D10--- *** Exception: user error (d10 must be between 0 and 9)------ >>> integralD10Fail ((-5) :: Integer) :: IO D10--- *** Exception: user error (d10 must be between 0 and 9)--integralD10Fail :: (Integral a, MonadFail m) => a -> m D10-integralD10Fail x =-    case (integralD10Maybe x) of-        Just y  -> return y-        Nothing -> fail "d10 must be between 0 and 9"--------------------------------------------------------- | Produces an expression of type @['D10']@ that can be used--- in a Template Haskell splice.------ >>> $(d10ListExp "")--- []------ >>> $(d10ListExp "5")--- [D5]------ >>> $(d10ListExp "58")--- [D5,D8]------ >>> $(d10ListExp "a")--- ...--- ... d10 must be between 0 and 9--- ...------ You may also be interested in 'd10list', a quasi-quoter which--- does something similar.--d10ListExp :: String -> Q Exp-d10ListExp = strD10ListFail >=> d10ListExp'--d10ListExp' :: [D10] -> Q Exp-d10ListExp' x = [| x |]-------------------------------------------------------d10Pat :: D10 -> Q Pat-d10Pat = dataToPatQ (const Nothing)---- | Produces a pattern that can be used in a splice--- to match a particular list of 'D10' values.------ >>> :{---       case [D5, D6] of---         $(d10ListPat "42") -> "A"---         $(d10ListPat "56") -> "B"---         _                  -> "C"--- >>> :}--- "B"------ You may also be interested in 'd10list', a quasi-quoter which--- does something similar.--d10ListPat :: String -> Q Pat-d10ListPat = strD10ListFail >=> \xs ->-  do-    pats <- traverse d10Pat xs-    return (ListP pats)--d10ListPat' :: [D10] -> Q Pat-d10ListPat' xs =-  do-    pats <- traverse d10Pat xs-    return (ListP pats)--------------------------------------------------------- | A list of base-10 digits.------ This quasi-quoter, when used as an expression, produces a--- value of type @['D10']@.------ >>> [d10list||]--- []------ >>> [d10list|5|]--- [D5]------ >>> [d10list|58|]--- [D5,D8]------ >>> [d10list|a|]--- ...--- ... d10 must be between 0 and 9--- ...------ This quasi-quoter can also be used as a pattern.------ >>> :{---       case [D5, D6] of---         [d10list|41|] -> "A"---         [d10list|56|] -> "B"---         _             -> "C"--- >>> :}--- "B"------ >>> :{---       case [D5, D6] of---         [d10list|4x|] -> "A"---         [d10list|56|] -> "B"---         _             -> "C"--- >>> :}--- ...--- ... d10 must be between 0 and 9--- ...--d10list :: QuasiQuoter-d10list = QuasiQuoter-    { quoteExp  = strD10ListFail >=> d10ListExp'-    , quotePat  = strD10ListFail >=> d10ListPat'-    , quoteType = \_ -> fail "d10list cannot be used in a type context"-    , quoteDec  = \_ -> fail "d10list cannot be used in a declaration context"-    }--------------------------------------------------------- | Addition modulo 10.------ >>> D2 + D3--- D5------ >>> D6 + D7--- D3--(+) :: D10 -> D10 -> D10-x + y = intMod10 (d10Int x P.+ d10Int y)---- | Subtraction modulo 10.------ >>> D7 - D5--- D2------ >>> D3 - D7--- D6--(-) :: D10 -> D10 -> D10-x - y = intMod10 (d10Int x P.- d10Int y)---- | Multiplication modulo 10.------ >>> D2 * D4--- D8--- >>> D7 * D8--- D6--(*) :: D10 -> D10 -> D10-x * y = intMod10 (d10Int x P.* d10Int y)
test/char.hs view
@@ -1,7 +1,8 @@ import Prelude hiding (fail, (+), (-), (*)) -import Data.D10.Char-import qualified Data.D10.Predicate as Predicate+import D10.Char+import D10.Char.Arithmetic+import qualified D10.Predicate as Predicate  import Hedgehog import qualified Hedgehog.Gen as Gen
test/num.hs view
@@ -1,7 +1,8 @@ import Prelude hiding (fail, (+), (-), (*)) -import Data.D10.Num-import qualified Data.D10.Predicate as Predicate+import D10.Num+import D10.Num.Arithmetic+import qualified D10.Predicate as Predicate  import Hedgehog import qualified Hedgehog.Gen as Gen
test/safe.hs view
@@ -1,7 +1,8 @@ import Prelude hiding (fail, (+), (-), (*)) -import Data.D10.Safe-import qualified Data.D10.Predicate as Predicate+import D10.Safe+import D10.Safe.Arithmetic+import qualified D10.Predicate as Predicate  import Hedgehog import qualified Hedgehog.Gen as Gen