我正在尝试构建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
函数中。我不太确定。
答案 0 :(得分:1)
在optparse-applicative中,有Parser
类型,还有ParserInfo
类型,它表示“完整”解析器,其中包含额外的信息,例如页眉,页脚,描述等,并且已经准备就绪与execParser
一起运行。
我们通过info
函数从Parser
到ParserInfo
,该函数将额外的信息添加为修饰符。
现在,当使用子命令编写解析器时,每个子命令必须具有自己的ParserInfo
值(这意味着它可以具有自己的本地帮助和描述)。
我们将每个ParserInfo
值传递给command
函数(以及我们希望子命令具有的名称),然后使用{{1}组合[Mod CommandFields JournalCommand]
列表},并将结果传递到subparser
。这将为我们提供顶级mconcat
。我们需要再次使用Parser
来提供顶层描述并获得最终的info
。
使用您的类型的简化版本的示例:
ParserInfo