使用OptParse-Applicative将用户选项解析为自定义数据类型

时间:2019-07-23 15:59:37

标签: haskell optparse-applicative

我正在尝试构建CLI食品日记应用程序。

这是我希望解析用户输入的数据类型。

data JournalCommand =
  JournalSearch Query DataTypes Ingridents BrandOwnder PageNumber
  | JournalReport Query DataTypes Ingridents BrandOwnder PageNumber ResultNumber
  | JournalDisplay FromDate ToDate ResultNumber
  | JournalStoreSearch Query DataTypes Ingridents BrandOwnder PageNumber ResultNumber StoreFlag
  | JournalStoreCustom CustomEntry OnDate StoreFlag
  | JournalDelete FromDate ToDate ResultNumber
  | JournalEdit CustomEntry ResultNumber
  deriving (Show, Eq)

并且由于有很多重叠,所以我总共使用了Parser a类型的8个函数。

像这样的功能

-- | Search Query
aQueryParser :: Parser String
aQueryParser = strOption
               ( long "search"
                 <> short 's'
                 <> help "Search for a term in the database"
               )

最终拥有这样一个功能的想法

runJournal :: JournalCommand -> MT SomeError IO ()
runJournal = \case
             JournalSearch q d i b p
                     -> runSearch q d i b p
             JournalReport q d i b p r
                     -> runSearchAndReport q d i b p r
            ...
            ...

其中MT是一些可以处理error + IO的monad转换器。不确定。

问题是:如何设置parseArgs功能

parseArgs :: IO JournalCommand
parseArgs = execParser ...

parser函数

parser :: Parser JournalCommand
parser = ...

以便我能够将用户输入解析为JournalCommand,然后将数据返回给相关函数。

我知道我可以fmap这样的数据类型

data JournalDisplay { jdFromDate     :: UTCTime
                    , jdToDate       :: UTCTime
                    , jdResultNumber :: Maybe Int
                    }

JournalDisplay
<$>
fromDateParser
<*>
toDateParser
<*>
optional resultNumberParser

但是我不确定如何使用原始数据结构来做到这一点。

我认为我需要一个像[Mod CommandFields JournalCommand]这样的列表,我可以通过串联subparser列表将其传递到Mod函数中。我不太确定。

1 个答案:

答案 0 :(得分:1)

在optparse-applicative中,有Parser类型,还有ParserInfo类型,它表示“完整”解析器,其中包含额外的信息,例如页眉,页脚,描述等,并且已经准备就绪与execParser一起运行。  我们通过info函数从ParserParserInfo,该函数将额外的信息添加为修饰符。

现在,当使用子命令编写解析器时,每个子命令必须具有自己的ParserInfo值(这意味着它可以具有自己的本地帮助和描述)。

我们将每个ParserInfo值传递给command函数(以及我们希望子命令具有的名称),然后使用{{1}组合[Mod CommandFields JournalCommand]列表},并将结果传递到subparser。这将为我们提供顶级mconcat。我们需要再次使用Parser来提供顶层描述并获得最终的info

使用您的类型的简化版本的示例:

ParserInfo