我有一个基本命令add
,它接受两种参数:单词或标记。标签只是一个以+
开头的单词。单词只是String
。它可以包含至少一个参数(为此我使用some
)。
data Arg = Add AddOpts
data AddOpts = AddOpts
{ desc :: String,
tags :: [String]
}
deriving (Show)
addCommand :: Mod CommandFields Arg
addCommand = command "add" (info parser infoMod)
where
infoMod = progDesc "Add a new task"
parser = Add <$> parseDescAndTags <$> partition isTag <$> some (argument str (metavar "DESC"))
parseDescAndTags (_, []) = FAIL HERE
parseDescAndTags (tags, desc) = AddOpts (unwords desc) (map tail tags)
我想添加另一条规则:add
命令应至少接收一个单词(但0个或多个标签)。为此,我需要在第一次解析单词列表后进行检查。如果为空,我会失败,好像add
命令未收到任何参数,但我不知道该怎么做。
答案 0 :(得分:1)
size
当前是一个纯函数,因此无法导致解析失败。只是为了避免这种情况,我还应注意以下代码:
parseDescAndTags
运算符Add <$> parseDescAndTags <$> partition isTag <$> some (argument str (metavar "DESC"))
被声明为<$>
,因此它是左关联的,因此您的表达式等同于:
infixl 4
您碰巧在“函数阅读器”函子((Add <$> parseDescAndTags) <$> partition isTag) <$> some (argument str (metavar "DESC"))
中使用<$>
,相当于合成(->) a
:
(.)
如果要使用Add . parseDescAndTags . partition isTag <$> some (argument str (metavar "DESC"))
,则需要使用诸如eitherReader
之类的函数来构造ReadM
动作。但是问题在于,您需要将它用作ReadM
的第一个参数,而不是argument
的读者,这是错误的地方,因为str
在外部,并且您想根据整个选项的累加结果进行解析。
不幸的是,some
并不是为这种上下文敏感的解析而设计的;它不为解析器提供optparse-applicative
实例。
当前,您的解析器允许标签和描述进行交错,如下所示(假设以Monad
为例)
isTag = (== ".") . take 1
产生add some .tag1 description .tag2 text
作为描述,并产生"some description text"
作为标记。是您想要的,还是可以使用更简单的格式,例如在末尾要求所有标签?
[".tag1", ".tag2"]
如果是这样,结果很简单:使用add some description text .tag1 .tag2
解析至少一个非标签,然后使用some
解析任意数量的标签:
many
作为替代方案,您可以使用addCommand :: Mod CommandFields Arg
addCommand = command "add" (info parser infoMod)
where
infoMod = progDesc "Add a new task"
parser = Add <$> addOpts
addOpts = AddOpts
<$> (unwords <$> some (argument nonTag (metavar "DESC")))
<*> many (argument tag (metavar "TAG"))
nonTag = eitherReader
$ \ str -> if isTag str
then Left ("unexpected tag: '" <> str <> "'")
else Right str
tag = eitherReader
$ \ str -> if isTag str
then Right $ drop 1 str
else Left ("not a tag: '" <> str <> "'")
parse 命令行选项,但是在运行解析器后对选项记录进行任何更复杂的 validation 。然后,如果要手动打印帮助文本,可以使用:
optparse-applicative