2

我正在尝试构建一个 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)

而且因为有很多重叠,所以我总共有 8 个Parser a类型的函数。

像这样的功能

-- | 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?还不确定。

问题是:如何设置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。我不完全确定。

4

1 回答 1

2

在 optparse-applicative 中有Parser类型,但也有ParserInfo表示“已完成”解析器的类型,该解析器包含额外的信息,如页眉、页脚、描述等......并且可以使用execParser. 我们通过添加额外信息作为修饰符的函数来从Parser到。ParserInfoinfo

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

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

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

data JournalCommand =
    JournalSearch String String
  | JournalReport String
  deriving (Show, Eq)

journalParserInfo :: O.ParserInfo JournalCommand
journalParserInfo = 
    let searchParserInfo :: O.ParserInfo JournalCommand
        searchParserInfo = 
            O.info
            (JournalSearch 
                <$> strArgument (metavar "ARG1" <> help "This is arg 1")
                <*> strArgument (metavar "ARG2" <> help "This is arg 2"))
            (O.fullDesc <> O.progDesc "desc 1")
        reportParserInfo :: O.ParserInfo JournalCommand
        reportParserInfo = 
            O.info
            (JournalReport 
                <$> strArgument (metavar "ARG3" <> help "This is arg 3"))
            (O.fullDesc <> O.progDesc "desc 2")
        toplevel :: O.Parser JournalCommand
        toplevel = O.subparser (mconcat [ 
                command "search" searchParserInfo, 
                command "journal" reportParserInfo 
            ])
     in O.info toplevel (O.fullDesc <> O.progDesc "toplevel desc") 
于 2019-07-23T16:56:47.697 回答