packages feed

taiwan-id 0.0.0.0 → 0.1.0.0

raw patch · 10 files changed

+378/−291 lines, 10 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Taiwan.ID: getLocation :: ID -> Location
- Taiwan.ID: getNationality :: ID -> Nationality
- Taiwan.ID: setLocation :: Location -> ID -> ID
- Taiwan.ID: setNationality :: Nationality -> ID -> ID
- Taiwan.ID.Location: data Location
- Taiwan.ID.Location: fromLetter :: Letter -> Location
- Taiwan.ID.Location: generate :: MonadRandom m => m Location
- Taiwan.ID.Location: instance Data.Finitary.Finitary Taiwan.ID.Location.Location
- Taiwan.ID.Location: instance GHC.Classes.Eq Taiwan.ID.Location.Location
- Taiwan.ID.Location: instance GHC.Classes.Ord Taiwan.ID.Location.Location
- Taiwan.ID.Location: instance GHC.Enum.Bounded Taiwan.ID.Location.Location
- Taiwan.ID.Location: instance GHC.Enum.Enum Taiwan.ID.Location.Location
- Taiwan.ID.Location: instance GHC.Generics.Generic Taiwan.ID.Location.Location
- Taiwan.ID.Location: instance GHC.Read.Read Taiwan.ID.Location.Location
- Taiwan.ID.Location: instance GHC.Show.Show Taiwan.ID.Location.Location
- Taiwan.ID.Location: toLetter :: Location -> Letter
- Taiwan.ID.Location: toText :: Language -> Location -> Text
- Taiwan.ID.Nationality: National :: Nationality
- Taiwan.ID.Nationality: NonNational :: Nationality
- Taiwan.ID.Nationality: data Nationality
- Taiwan.ID.Nationality: generate :: MonadRandom m => m Nationality
- Taiwan.ID.Nationality: instance Data.Finitary.Finitary Taiwan.ID.Nationality.Nationality
- Taiwan.ID.Nationality: instance GHC.Classes.Eq Taiwan.ID.Nationality.Nationality
- Taiwan.ID.Nationality: instance GHC.Classes.Ord Taiwan.ID.Nationality.Nationality
- Taiwan.ID.Nationality: instance GHC.Enum.Bounded Taiwan.ID.Nationality.Nationality
- Taiwan.ID.Nationality: instance GHC.Enum.Enum Taiwan.ID.Nationality.Nationality
- Taiwan.ID.Nationality: instance GHC.Generics.Generic Taiwan.ID.Nationality.Nationality
- Taiwan.ID.Nationality: instance GHC.Read.Read Taiwan.ID.Nationality.Nationality
- Taiwan.ID.Nationality: instance GHC.Show.Show Taiwan.ID.Nationality.Nationality
+ Taiwan.ID: getIssuer :: ID -> Issuer
+ Taiwan.ID: getRegion :: ID -> Region
+ Taiwan.ID: setIssuer :: Issuer -> ID -> ID
+ Taiwan.ID: setRegion :: Region -> ID -> ID
+ Taiwan.ID.Issuer: HouseholdRegistrationOffice :: Issuer
+ Taiwan.ID.Issuer: NationalImmigrationAgency :: Issuer
+ Taiwan.ID.Issuer: data Issuer
+ Taiwan.ID.Issuer: generate :: MonadRandom m => m Issuer
+ Taiwan.ID.Issuer: instance Data.Finitary.Finitary Taiwan.ID.Issuer.Issuer
+ Taiwan.ID.Issuer: instance GHC.Classes.Eq Taiwan.ID.Issuer.Issuer
+ Taiwan.ID.Issuer: instance GHC.Classes.Ord Taiwan.ID.Issuer.Issuer
+ Taiwan.ID.Issuer: instance GHC.Enum.Bounded Taiwan.ID.Issuer.Issuer
+ Taiwan.ID.Issuer: instance GHC.Enum.Enum Taiwan.ID.Issuer.Issuer
+ Taiwan.ID.Issuer: instance GHC.Generics.Generic Taiwan.ID.Issuer.Issuer
+ Taiwan.ID.Issuer: instance GHC.Read.Read Taiwan.ID.Issuer.Issuer
+ Taiwan.ID.Issuer: instance GHC.Show.Show Taiwan.ID.Issuer.Issuer
+ Taiwan.ID.Issuer: toText :: Language -> Issuer -> Text
+ Taiwan.ID.Region: data Region
+ Taiwan.ID.Region: fromChar :: Char -> Maybe Region
+ Taiwan.ID.Region: fromLetter :: Letter -> Region
+ Taiwan.ID.Region: generate :: MonadRandom m => m Region
+ Taiwan.ID.Region: instance Data.Finitary.Finitary Taiwan.ID.Region.Region
+ Taiwan.ID.Region: instance GHC.Classes.Eq Taiwan.ID.Region.Region
+ Taiwan.ID.Region: instance GHC.Classes.Ord Taiwan.ID.Region.Region
+ Taiwan.ID.Region: instance GHC.Enum.Bounded Taiwan.ID.Region.Region
+ Taiwan.ID.Region: instance GHC.Enum.Enum Taiwan.ID.Region.Region
+ Taiwan.ID.Region: instance GHC.Generics.Generic Taiwan.ID.Region.Region
+ Taiwan.ID.Region: instance GHC.Read.Read Taiwan.ID.Region.Region
+ Taiwan.ID.Region: instance GHC.Show.Show Taiwan.ID.Region.Region
+ Taiwan.ID.Region: toChar :: Region -> Char
+ Taiwan.ID.Region: toLetter :: Region -> Letter
+ Taiwan.ID.Region: toText :: Language -> Region -> Text

Files

CHANGELOG.md view
@@ -1,3 +1,34 @@+# 0.1.0.0++- Replaced the `Location` type with a new `Region` type, reflecting the fact+  that the first character of an identification number represents an+  administrative area with geographic extent, rather than a specific point in+  space. Accordingly, replaced functions `ID.{get,set}Location` with+  `ID.{get,set}Region`.++- Replaced the `Nationality` type with a new `Issuer` type, reflecting the fact+  that the second character of an identification number encodes the government+  authority that issued the number, rather than the nationality of the holder.+  Accordingly, replaced functions `ID.{get,set}Nationality` with+  `ID.{get,set}Issuer`.++- Added `Region.fromChar` and `Region.toChar` for converting between `Region`+  values and their corresponding character codes.++- Fixed the `Show` and `Read` instances for `Region` to correctly handle+  operator precedence, ensuring that `Region` values are wrapped in parentheses+  when necessary.++- Added `Issuer.toText` for printing `Issuer` values in English and Chinese.++- Fixed incorrect use of "Alien Resident Certificate" (外僑居留證) terminology+  in the package description, replacing it with the correct umbrella term+  "Resident Certificate" (居留證).++- Fixed an internal inconsistency in `listToTuple8`, which previously accepted+  lists of more than 8 elements and silently discarded the excess elements. It+  now correctly requires exactly 8 elements.+ # 0.0.0.0  - Initial release.
README.md view
@@ -11,9 +11,9 @@ identification number format.  This number format is used by both National Identification Cards (國民身分證)-and Alien Resident Certificates (外僑居留證) issued by the Republic of China-(ROC) government to individuals, with numbers assigned under each system-occupying disjoint parts of the same identifier space.+and Resident Certificates (居留證) issued by the Republic of China (ROC)+government to individuals, with numbers assigned under each system occupying+disjoint parts of the same identifier space.  Each identification number consists of a single uppercase letter followed by nine decimal digits, with the final digit serving as a checksum calculated
components/taiwan-id-test/Spec.hs view
@@ -34,12 +34,12 @@   ( Digit1289 (..) ) import Taiwan.ID.Gender   ( Gender (..) )+import Taiwan.ID.Issuer+  ( Issuer (..) ) import Taiwan.ID.Letter   ( Letter (..) )-import Taiwan.ID.Location-  ( Location )-import Taiwan.ID.Nationality-  ( Nationality (..) )+import Taiwan.ID.Region+  ( Region ) import Test.Hspec   ( Spec, describe, hspec, it, shouldBe, shouldSatisfy ) import Test.QuickCheck@@ -77,22 +77,22 @@   arbitrary = arbitraryBoundedEnum   shrink = shrinkBoundedEnum -instance Arbitrary Letter where-  arbitrary = arbitraryBoundedEnum-  shrink = shrinkBoundedEnum- instance Arbitrary ID where   arbitrary = idFromTuple <$> arbitrary   shrink = shrinkMap idFromTuple idToTuple -instance Arbitrary Location where+instance Arbitrary Issuer where   arbitrary = arbitraryBoundedEnum   shrink = shrinkBoundedEnum -instance Arbitrary Nationality where+instance Arbitrary Letter where   arbitrary = arbitraryBoundedEnum   shrink = shrinkBoundedEnum +instance Arbitrary Region where+  arbitrary = arbitraryBoundedEnum+  shrink = shrinkBoundedEnum+ main :: IO () main = hspec $ do @@ -122,7 +122,7 @@         , showReadLaws         ] -    testLawsMany @Location+    testLawsMany @Issuer         [ boundedEnumLaws         , eqLaws         , ordLaws@@ -130,7 +130,7 @@         , showReadLaws         ] -    testLawsMany @Nationality+    testLawsMany @Region         [ boundedEnumLaws         , eqLaws         , ordLaws@@ -175,10 +175,10 @@      describe "Gender" $       checkLensLaws gender-    describe "Location" $-      checkLensLaws location-    describe "Nationality" $-      checkLensLaws nationality+    describe "Issuer" $+      checkLensLaws issuer+    describe "Region" $+      checkLensLaws region    describe "ID.fromText" $ do @@ -201,10 +201,10 @@         let invalidID = ID.toText i <> T.pack s         ID.fromText invalidID `shouldBe` Left ID.InvalidLength -    it "does not parse identification numbers with invalid location codes" $+    it "does not parse identification numbers with invalid region codes" $       property $ \(i :: ID) (c :: Int) -> do-        let invalidLocationCode = intToDigit $ c `mod` 10-        let invalidID = replaceCharAt 0 invalidLocationCode $ ID.toText i+        let invalidRegionCode = intToDigit $ c `mod` 10+        let invalidID = replaceCharAt 0 invalidRegionCode $ ID.toText i         ID.fromText invalidID `shouldBe`           Left (ID.InvalidChar 0 (CharRange 'A' 'Z')) @@ -280,11 +280,11 @@ gender :: Lens' ID Gender gender = lens ID.getGender (flip ID.setGender) -location :: Lens' ID Location-location = lens ID.getLocation (flip ID.setLocation)+issuer :: Lens' ID Issuer+issuer = lens ID.getIssuer (flip ID.setIssuer) -nationality :: Lens' ID Nationality-nationality = lens ID.getNationality (flip ID.setNationality)+region :: Lens' ID Region+region = lens ID.getRegion (flip ID.setRegion)  -- | Replaces a character at a specific position. --
components/taiwan-id/Taiwan/ID.hs view
@@ -30,13 +30,13 @@    -- * Inspection   , getGender-  , getLocation-  , getNationality+  , getIssuer+  , getRegion    -- * Modification   , setGender-  , setLocation-  , setNationality+  , setIssuer+  , setRegion   )   where @@ -64,12 +64,12 @@   ( Digit1289 (..) ) import Taiwan.ID.Gender   ( Gender (..) )+import Taiwan.ID.Issuer+  ( Issuer (..) ) import Taiwan.ID.Letter   ( Letter (..) )-import Taiwan.ID.Location-  ( Location )-import Taiwan.ID.Nationality-  ( Nationality (..) )+import Taiwan.ID.Region+  ( Region ) import Taiwan.ID.Unchecked   ( UncheckedID (UncheckedID), ValidID ) import Taiwan.ID.Utilities@@ -78,7 +78,7 @@   ( Lexeme (Ident, Symbol, Punc), Read (readPrec), lexP, parens, prec )  import qualified Data.Text as T-import qualified Taiwan.ID.Location as Location+import qualified Taiwan.ID.Region as Region import qualified Taiwan.ID.Unchecked as U  -- |@@ -306,15 +306,15 @@ getGender :: ID -> Gender getGender ID {c1} = fst $ decodeC1 c1 --- | Decodes the 'Location' component of an 'ID'.+-- | Decodes the 'Issuer' component of an 'ID'. ---getLocation :: ID -> Location-getLocation ID {c0} = Location.fromLetter c0+getIssuer :: ID -> Issuer+getIssuer ID {c1} = snd $ decodeC1 c1 --- | Decodes the 'Nationality' component of an 'ID'.+-- | Decodes the 'Region' component of an 'ID'. ---getNationality :: ID -> Nationality-getNationality ID {c1} = snd $ decodeC1 c1+getRegion :: ID -> Region+getRegion ID {c0} = Region.fromLetter c0  -------------------------------------------------------------------------------- -- Modification@@ -323,35 +323,35 @@ -- | Updates the 'Gender' component of an 'ID'. -- setGender :: Gender -> ID -> ID-setGender gender i = i {c1 = encodeC1 (gender, getNationality i)}+setGender gender i = i {c1 = encodeC1 (gender, getIssuer i)} --- | Updates the 'Location' component of an 'ID'.+-- | Updates the 'Issuer' component of an 'ID'. ---setLocation :: Location -> ID -> ID-setLocation location i = i {c0 = Location.toLetter location}+setIssuer :: Issuer -> ID -> ID+setIssuer issuer i = i {c1 = encodeC1 (getGender i, issuer)} --- | Updates the 'Nationality' component of an 'ID'.+-- | Updates the 'Region' component of an 'ID'. ---setNationality :: Nationality -> ID -> ID-setNationality nationality i = i {c1 = encodeC1 (getGender i, nationality)}+setRegion :: Region -> ID -> ID+setRegion region i = i {c0 = Region.toLetter region}  -------------------------------------------------------------------------------- -- Internal -------------------------------------------------------------------------------- -decodeC1 :: Digit1289 -> (Gender, Nationality)+decodeC1 :: Digit1289 -> (Gender, Issuer) decodeC1 = \case-  D1289_1 -> (  Male,    National)-  D1289_2 -> (Female,    National)-  D1289_8 -> (  Male, NonNational)-  D1289_9 -> (Female, NonNational)+  D1289_1 -> (  Male, HouseholdRegistrationOffice)+  D1289_2 -> (Female, HouseholdRegistrationOffice)+  D1289_8 -> (  Male,   NationalImmigrationAgency)+  D1289_9 -> (Female,   NationalImmigrationAgency) -encodeC1 :: (Gender, Nationality) -> Digit1289+encodeC1 :: (Gender, Issuer) -> Digit1289 encodeC1 = \case-  (  Male,    National) -> D1289_1-  (Female,    National) -> D1289_2-  (  Male, NonNational) -> D1289_8-  (Female, NonNational) -> D1289_9+  (  Male, HouseholdRegistrationOffice) -> D1289_1+  (Female, HouseholdRegistrationOffice) -> D1289_2+  (  Male,   NationalImmigrationAgency) -> D1289_8+  (Female,   NationalImmigrationAgency) -> D1289_9  fromUnchecked :: UncheckedID -> Maybe ID fromUnchecked u@(UncheckedID u0 u1 u2 u3 u4 u5 u6 u7 u8 _) =
+ components/taiwan-id/Taiwan/ID/Issuer.hs view
@@ -0,0 +1,59 @@+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}++module Taiwan.ID.Issuer+  ( Issuer (..)+  , toText+  , generate+  )+  where++import Control.Monad.Random.Class+  ( MonadRandom (..) )+import Data.Finitary+  ( Finitary )+import Data.Text+  ( Text )+import GHC.Generics+  ( Generic )+import Taiwan.ID.Language+  ( Language (English, Chinese) )+import Taiwan.ID.Utilities+  ( randomFinitary )++-- | A government authority that issues identification numbers.+--+data Issuer+  = HouseholdRegistrationOffice+  | NationalImmigrationAgency+  deriving stock (Bounded, Enum, Eq, Ord, Generic, Read, Show)+  deriving anyclass Finitary++-- | Generates a random 'Issuer'.+--+generate :: MonadRandom m => m Issuer+generate = randomFinitary++-- | Prints the specified 'Issuer'.+--+toText :: Language -> Issuer -> Text+toText = \case+  English -> toTextEnglish+  Chinese -> toTextChinese++toTextChinese :: Issuer -> Text+toTextChinese = \case+  HouseholdRegistrationOffice ->+    "戶政事務所"+  NationalImmigrationAgency ->+    "移民署"++toTextEnglish :: Issuer -> Text+toTextEnglish = \case+  HouseholdRegistrationOffice ->+    "Household Registration Office"+  NationalImmigrationAgency ->+    "National Immigration Agency"
− components/taiwan-id/Taiwan/ID/Location.hs
@@ -1,197 +0,0 @@-{-# LANGUAGE DeriveAnyClass #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE DerivingStrategies #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE OverloadedStrings #-}--module Taiwan.ID.Location-  ( Location-  , fromLetter-  , toLetter-  , toText-  , generate-  ) where--import Control.Monad.Random.Class-  ( MonadRandom (..) )-import Data.Finitary-  ( Finitary )-import Data.Text-  ( Text )-import GHC.Generics-  ( Generic )-import Taiwan.ID.Language-  ( Language (..) )-import Taiwan.ID.Letter-  ( Letter (..) )-import Taiwan.ID.Utilities-  ( randomFinitary )-import Text.Read-  ( Lexeme (Ident, Symbol), Read (readPrec), lexP, parens )---- | Represents a geographical location.------ == Location codes------ Every location has a unique letter code:------ +------+---------+-------------------+--- | Code | Chinese | English           |--- +======+=========+===================+--- | @A@  | 臺北市     | Taipei City       |--- +------+---------+-------------------+--- | @B@  | 臺中市     | Taichung City     |--- +------+---------+-------------------+--- | @C@  | 基隆市     | Keelung City      |--- +------+---------+-------------------+--- | @D@  | 臺南市     | Tainan City       |--- +------+---------+-------------------+--- | @E@  | 高雄市     | Kaohsiung City    |--- +------+---------+-------------------+--- | @F@  | 新北市     | New Taipei City   |--- +------+---------+-------------------+--- | @G@  | 宜蘭縣     | Yilan County      |--- +------+---------+-------------------+--- | @H@  | 桃園市     | Taoyuan City      |--- +------+---------+-------------------+--- | @I@  | 嘉義市     | Chiayi City       |--- +------+---------+-------------------+--- | @J@  | 新竹縣     | Hsinchu County    |--- +------+---------+-------------------+--- | @K@  | 苗栗縣     | Miaoli County     |--- +------+---------+-------------------+--- | @L@  | 臺中縣     | Taichung County   |--- +------+---------+-------------------+--- | @M@  | 南投縣     | Nantou County     |--- +------+---------+-------------------+--- | @N@  | 彰化縣     | Changhua County   |--- +------+---------+-------------------+--- | @O@  | 新竹市     | Hsinchu City      |--- +------+---------+-------------------+--- | @P@  | 雲林縣     | Yunlin County     |--- +------+---------+-------------------+--- | @Q@  | 嘉義縣     | Chiayi County     |--- +------+---------+-------------------+--- | @R@  | 臺南縣     | Tainan County     |--- +------+---------+-------------------+--- | @S@  | 高雄縣     | Kaohsiung County  |--- +------+---------+-------------------+--- | @T@  | 屏東縣     | Pingtung County   |--- +------+---------+-------------------+--- | @U@  | 花蓮縣     | Hualien County    |--- +------+---------+-------------------+--- | @V@  | 臺東縣     | Taitung County    |--- +------+---------+-------------------+--- | @W@  | 金門縣     | Kinmen County     |--- +------+---------+-------------------+--- | @X@  | 澎湖縣     | Penghu County     |--- +------+---------+-------------------+--- | @Y@  | 陽明山     | Yangmingshan      |--- +------+---------+-------------------+--- | @Z@  | 連江縣     | Lienchiang County |--- +------+---------+-------------------+------ == Usage------ To construct a 'Location' from its letter code, use the 'fromLetter'--- function.------ To print the full name of a 'Location', use the 'toText' function.------ To generate a random 'Location', use the 'generate' function.----newtype Location = Location Letter-  deriving stock (Eq, Generic, Ord)-  deriving newtype (Bounded, Enum)-  deriving anyclass Finitary--instance Read Location where-  readPrec = parens $ do-    Ident "Location"   <- lexP-    Symbol "."         <- lexP-    Ident "fromLetter" <- lexP-    fromLetter <$> readPrec--instance Show Location where-  showsPrec _ s =-    showString "Location.fromLetter " . shows (toLetter s)---- | Constructs a 'Location' from its corresponding letter code.----fromLetter :: Letter -> Location-fromLetter = Location---- | Converts a 'Location' to its corresponding letter code.----toLetter :: Location -> Letter-toLetter (Location letter) = letter---- | Prints the specified 'Location'.-toText :: Language -> Location -> Text-toText = \case-  English -> toTextEnglish-  Chinese -> toTextChinese--toTextChinese :: Location -> Text-toTextChinese (Location letter) = case letter of-  A -> "臺北市"-  B -> "臺中市"-  C -> "基隆市"-  D -> "臺南市"-  E -> "高雄市"-  F -> "新北市"-  G -> "宜蘭縣"-  H -> "桃園市"-  I -> "嘉義市"-  J -> "新竹縣"-  K -> "苗栗縣"-  L -> "臺中縣"-  M -> "南投縣"-  N -> "彰化縣"-  O -> "新竹市"-  P -> "雲林縣"-  Q -> "嘉義縣"-  R -> "臺南縣"-  S -> "高雄縣"-  T -> "屏東縣"-  U -> "花蓮縣"-  V -> "臺東縣"-  W -> "金門縣"-  X -> "澎湖縣"-  Y -> "陽明山"-  Z -> "連江縣"--toTextEnglish :: Location -> Text-toTextEnglish (Location letter) = case letter of-  A -> "Taipei City"-  B -> "Taichung City"-  C -> "Keelung City"-  D -> "Tainan City"-  E -> "Kaohsiung City"-  F -> "New Taipei City"-  G -> "Yilan County"-  H -> "Taoyuan City"-  I -> "Chiayi City"-  J -> "Hsinchu County"-  K -> "Miaoli County"-  L -> "Taichung County"-  M -> "Nantou County"-  N -> "Changhua County"-  O -> "Hsinchu City"-  P -> "Yunlin County"-  Q -> "Chiayi County"-  R -> "Tainan County"-  S -> "Kaohsiung County"-  T -> "Pingtung County"-  U -> "Hualien County"-  V -> "Taitung County"-  W -> "Kinmen County"-  X -> "Penghu County"-  Y -> "Yangmingshan"-  Z -> "Lienchiang County"---- | Generates a random 'Location'.----generate :: MonadRandom m => m Location-generate = randomFinitary
− components/taiwan-id/Taiwan/ID/Nationality.hs
@@ -1,29 +0,0 @@-{-# LANGUAGE DeriveAnyClass #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE DerivingStrategies #-}--module Taiwan.ID.Nationality-  ( Nationality (..)-  , generate-  )-  where--import Control.Monad.Random.Class-  ( MonadRandom (..) )-import Data.Finitary-  ( Finitary )-import GHC.Generics-  ( Generic )-import Taiwan.ID.Utilities-  ( randomFinitary )---- | Specifies a person's nationality.----data Nationality = National | NonNational-  deriving stock (Bounded, Enum, Eq, Ord, Generic, Read, Show)-  deriving anyclass Finitary---- | Generates a random 'Nationality'.----generate :: MonadRandom m => m Nationality-generate = randomFinitary
+ components/taiwan-id/Taiwan/ID/Region.hs view
@@ -0,0 +1,223 @@+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}++module Taiwan.ID.Region+  ( Region+  , fromChar+  , fromLetter+  , toChar+  , toLetter+  , toText+  , generate+  ) where++import Control.Monad.Random.Class+  ( MonadRandom (..) )+import Data.Finitary+  ( Finitary )+import Data.Text+  ( Text )+import GHC.Generics+  ( Generic )+import Taiwan.ID.Language+  ( Language (..) )+import Taiwan.ID.Letter+  ( Letter (..) )+import Taiwan.ID.Utilities+  ( randomFinitary )+import Text.Read+  ( Lexeme (Ident, Symbol), Read (readPrec), lexP, parens, prec )++import qualified Taiwan.ID.Letter as Letter++-- |+-- $setup+-- >>> import qualified Taiwan.ID.Region as Region++-- | Represents a geographical region.+--+-- == Region codes+--+-- Every region has a unique letter code:+--+-- +------+---------+-------------------++-- | Code | Chinese | English           |+-- +======+=========+===================++-- | @A@  | 臺北市     | Taipei City       |+-- +------+---------+-------------------++-- | @B@  | 臺中市     | Taichung City     |+-- +------+---------+-------------------++-- | @C@  | 基隆市     | Keelung City      |+-- +------+---------+-------------------++-- | @D@  | 臺南市     | Tainan City       |+-- +------+---------+-------------------++-- | @E@  | 高雄市     | Kaohsiung City    |+-- +------+---------+-------------------++-- | @F@  | 新北市     | New Taipei City   |+-- +------+---------+-------------------++-- | @G@  | 宜蘭縣     | Yilan County      |+-- +------+---------+-------------------++-- | @H@  | 桃園市     | Taoyuan City      |+-- +------+---------+-------------------++-- | @I@  | 嘉義市     | Chiayi City       |+-- +------+---------+-------------------++-- | @J@  | 新竹縣     | Hsinchu County    |+-- +------+---------+-------------------++-- | @K@  | 苗栗縣     | Miaoli County     |+-- +------+---------+-------------------++-- | @L@  | 臺中縣     | Taichung County   |+-- +------+---------+-------------------++-- | @M@  | 南投縣     | Nantou County     |+-- +------+---------+-------------------++-- | @N@  | 彰化縣     | Changhua County   |+-- +------+---------+-------------------++-- | @O@  | 新竹市     | Hsinchu City      |+-- +------+---------+-------------------++-- | @P@  | 雲林縣     | Yunlin County     |+-- +------+---------+-------------------++-- | @Q@  | 嘉義縣     | Chiayi County     |+-- +------+---------+-------------------++-- | @R@  | 臺南縣     | Tainan County     |+-- +------+---------+-------------------++-- | @S@  | 高雄縣     | Kaohsiung County  |+-- +------+---------+-------------------++-- | @T@  | 屏東縣     | Pingtung County   |+-- +------+---------+-------------------++-- | @U@  | 花蓮縣     | Hualien County    |+-- +------+---------+-------------------++-- | @V@  | 臺東縣     | Taitung County    |+-- +------+---------+-------------------++-- | @W@  | 金門縣     | Kinmen County     |+-- +------+---------+-------------------++-- | @X@  | 澎湖縣     | Penghu County     |+-- +------+---------+-------------------++-- | @Y@  | 陽明山     | Yangmingshan      |+-- +------+---------+-------------------++-- | @Z@  | 連江縣     | Lienchiang County |+-- +------+---------+-------------------++--+-- == Usage+--+-- To construct a 'Region' from its letter code, use the 'fromLetter'+-- function.+--+-- To print the full name of a 'Region', use the 'toText' function.+--+-- To generate a random 'Region', use the 'generate' function.+--+newtype Region = Region Letter+  deriving stock (Eq, Generic, Ord)+  deriving newtype (Bounded, Enum)+  deriving anyclass Finitary++instance Read Region where+  readPrec = parens $ prec 10 $ do+    Ident "Region"     <- lexP+    Symbol "."         <- lexP+    Ident "fromLetter" <- lexP+    fromLetter <$> readPrec++instance Show Region where+  showsPrec d s =+    showParen (d > 10) $+      showString "Region.fromLetter " . shows (toLetter s)++-- | Attempts to construct a 'Region' from its corresponding letter code as a+-- 'Char'.+--+-- >>> Region.fromChar 'A'+-- Just (Region.fromLetter A)+--+-- >>> Region.fromChar '?'+-- Nothing+--+fromChar :: Char -> Maybe Region+fromChar = fmap fromLetter . Letter.fromChar++-- | Constructs a 'Region' from its corresponding letter code.+--+fromLetter :: Letter -> Region+fromLetter = Region++-- | Converts a 'Region' to its corresponding letter code as a 'Char'.+--+toChar :: Region -> Char+toChar = Letter.toChar . toLetter++-- | Converts a 'Region' to its corresponding letter code.+--+toLetter :: Region -> Letter+toLetter (Region letter) = letter++-- | Prints the specified 'Region'.+toText :: Language -> Region -> Text+toText = \case+  English -> toTextEnglish+  Chinese -> toTextChinese++toTextChinese :: Region -> Text+toTextChinese (Region letter) = case letter of+  A -> "臺北市"+  B -> "臺中市"+  C -> "基隆市"+  D -> "臺南市"+  E -> "高雄市"+  F -> "新北市"+  G -> "宜蘭縣"+  H -> "桃園市"+  I -> "嘉義市"+  J -> "新竹縣"+  K -> "苗栗縣"+  L -> "臺中縣"+  M -> "南投縣"+  N -> "彰化縣"+  O -> "新竹市"+  P -> "雲林縣"+  Q -> "嘉義縣"+  R -> "臺南縣"+  S -> "高雄縣"+  T -> "屏東縣"+  U -> "花蓮縣"+  V -> "臺東縣"+  W -> "金門縣"+  X -> "澎湖縣"+  Y -> "陽明山"+  Z -> "連江縣"++toTextEnglish :: Region -> Text+toTextEnglish (Region letter) = case letter of+  A -> "Taipei City"+  B -> "Taichung City"+  C -> "Keelung City"+  D -> "Tainan City"+  E -> "Kaohsiung City"+  F -> "New Taipei City"+  G -> "Yilan County"+  H -> "Taoyuan City"+  I -> "Chiayi City"+  J -> "Hsinchu County"+  K -> "Miaoli County"+  L -> "Taichung County"+  M -> "Nantou County"+  N -> "Changhua County"+  O -> "Hsinchu City"+  P -> "Yunlin County"+  Q -> "Chiayi County"+  R -> "Tainan County"+  S -> "Kaohsiung County"+  T -> "Pingtung County"+  U -> "Hualien County"+  V -> "Taitung County"+  W -> "Kinmen County"+  X -> "Penghu County"+  Y -> "Yangmingshan"+  Z -> "Lienchiang County"++-- | Generates a random 'Region'.+--+generate :: MonadRandom m => m Region+generate = randomFinitary
components/taiwan-id/Taiwan/ID/Unchecked.hs view
@@ -173,7 +173,7 @@  listToTuple8 :: [a] -> Maybe (a, a, a, a, a, a, a, a) listToTuple8 = \case-  (a0 : a1 : a2 : a3 : a4 : a5 : a6 : a7 : _) ->+  [a0, a1, a2, a3, a4, a5, a6, a7] ->     Just (a0, a1, a2, a3, a4, a5, a6, a7)   _ ->     Nothing
taiwan-id.cabal view
@@ -1,6 +1,6 @@ cabal-version:  3.0 name:           taiwan-id-version:        0.0.0.0+version:        0.1.0.0 synopsis:       Implementation of Taiwan's uniform ID number format. category:       Identification homepage:       https://github.com/jonathanknowles/taiwan-id#readme@@ -18,9 +18,9 @@   identification number format.    This number format is used by both National Identification Cards (國民身分證)-  and Alien Resident Certificates (外僑居留證) issued by the Republic of China-  (ROC) government to individuals, with numbers assigned under each system-  occupying disjoint parts of the same identifier space.+  and Resident Certificates (居留證) issued by the Republic of China (ROC)+  government to individuals, with numbers assigned under each system occupying+  disjoint parts of the same identifier space.    Each identification number consists of a single uppercase letter followed by   nine decimal digits, with the final digit serving as a checksum calculated@@ -90,10 +90,10 @@       Taiwan.ID.Digit       Taiwan.ID.Digit1289       Taiwan.ID.Gender+      Taiwan.ID.Issuer       Taiwan.ID.Language       Taiwan.ID.Letter-      Taiwan.ID.Location-      Taiwan.ID.Nationality+      Taiwan.ID.Region   other-modules:       Taiwan.ID.Unchecked       Taiwan.ID.Utilities