Making an 'optional' parser using optparse-applicative and constructing value for recursive data type

90 Views Asked by At

I have a data type called EntrySearchableInfo written like this

type EntryDate = UTCTime -- From Data.Time

type EntryTag = Tag -- String

type EntryName = Name -- String

type EntryDescription = Description -- String

type EntryId = Int
data EntrySearchableInfo
  = SearchableEntryDate EntryDate
  | SearchableEntryTag EntryTag
  | SearchableEntryName EntryName
  | SearchableEntryDescription EntryDescription
  | SearchableEntryId EntryId

Basically represents things that make sense in 'search' context.

I want to write a function with this type

entrySearchableInfoParser :: Parser (Either String EntrySearchableInfo)

which (I think) will be a combination of several primitive Parser <Type> functions I have already written

entryDateParser :: Parser (Either String UTCTime)
entryDateParser = parseStringToUTCTime <$> strOption
  (long "date" <> short 'd' <> metavar "DATE" <> help entryDateParserHelp)

searchableEntryDateParser :: Parser (Either String EntrySearchableInfo)
searchableEntryDateParser = SearchableEntryDate <$$> entryDateParser -- <$$> is just (fmap . fmap)

searchableEntryTagParser :: Parser (Either String EntrySearchableInfo)
searchableEntryTagParser = ...
...

So I have two questions:

  1. How do I combine those parsers to make entrySearchableInfoParser functions.

  2. EntrySearchableInfo type is a part of a larger Entry type defined like this

data Entry
    = Add EntryDate EntryInfo EntryTag EntryNote EntryId
    | Replace EntrySearchableInfo Entry
    | ...
    ...

I already have a function with type

entryAdd :: Parser (Either String Entry) 

which constructs Entry using Add.

But I'm not sure how to make Entry type using Replace with entrySearchableInfoParser and entryAdd.

1

There are 1 best solutions below

0
atis On BEST ANSWER

So combining those parsers were a lot simpler than I imagined.

I just had to use <|>

entrySearchableInfoParser :: Parser (Either String EntrySearchableInfo)
entrySearchableInfoParser =
  searchableEntryDateParser
    <|> searchableEntryTagParser
    <|> searchableEntryNameParser
    <|> searchableEntryDescriptionParser
    <|> searchableEntryIdParser

and constructing Entry type using Replace with entrySearchableInfoParser and entryAdd was too.

entryAdd :: Parser (Either String Entry)
entryAdd = ...

entryReplace :: Parser (Either String Entry)
entryReplace = liftA2 Edit <$> entrySearchableInfoParser <*> entryAdd

Now it works perfectly!