Keep successful values instead of throwing them away when validating
Note
When validating, many programs throw away the successful results of a validation if it's successful (for example by validating with a boolean function). What we can do instead is to parse the "good" value into a type of our own and continue using it in our program.
Functional languages can perform this very well with types and parser combinators.
We should be weary of shotgun parsing - mixing parsing and validating in one place, with the business logic as well, hoping that one of them catches any errors that may occur.
An example of parsing a passport and returning a value of the Passport
type
data Passport = Passport
{ birthYear :: Int,
issueYear :: Int,
expirationYear :: Int,
height :: String,
hairColor :: String,
eyeColor :: String,
passportId :: String,
countryId :: Maybe Int
}
passportParser :: Parser Passport
passportParser =
Passport <$$> byrParser -- <$$> builds the type
<||> iyrParser -- <||> required field
<||> P.try eyrParser -- P.try - lookahead parser
<||> P.try heightParser
<||> P.try hairColorParser
<||> P.try eyeColorParser
<||> passportIdParser
<|?> (Nothing, Just <$> countryIdParser) -- <|?> optional field