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 +31/−0
- README.md +3/−3
- components/taiwan-id-test/Spec.hs +23/−23
- components/taiwan-id/Taiwan/ID.hs +32/−32
- components/taiwan-id/Taiwan/ID/Issuer.hs +59/−0
- components/taiwan-id/Taiwan/ID/Location.hs +0/−197
- components/taiwan-id/Taiwan/ID/Nationality.hs +0/−29
- components/taiwan-id/Taiwan/ID/Region.hs +223/−0
- components/taiwan-id/Taiwan/ID/Unchecked.hs +1/−1
- taiwan-id.cabal +6/−6
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