haskelloptparse-applicative

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


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.


Solution

  • 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!