繁体   English   中英

Haskell ReadP 至少解​​析一个列表

[英]Haskell ReadP parse at least one of the list

我尝试使用 ReadP 标准库解析命令(创建)。 我的命令应该以字符串create开头,然后至少包含一个词/标签/到期,可能还有一个选项。 这是我的实际表达:

createExpr :: ReadP [Arg]
createExpr = do
  skipSpaces
  cmd <- SetCmd <$> cmdAliasExpr ["create", "add"]
  skipSpaces
  rest <-
    many1
    $   (AddWord <$> wordExpr)
    <|> (AddTag <$> addTagExpr)
    <|> (SetDue <$> dueExpr)
    <|> (AddOpt <$> optExpr)
  skipSpaces
  return $ cmd : rest

问题是,如果我只用一个选项调用create ,它解析得很好。 但它不应该,因为我期望至少有一个词/标签/到期。 我该如何表达?


[编辑] 感谢@M ,我找到了解决方案 阿鲁西

事实上,我使用了错误的运算符。 <++本地的、排他的、偏左的选择,更适合我的需求。 一旦匹配了一个表达式,它就不应该检查其他的:

notAnOpt arg = case arg of
  AddOpt _ -> False
  _        -> True


createExpr :: ReadP [Arg]
createExpr = do
  skipSpaces
  cmd <- SetCmd <$> cmdAliasExpr ["create", "add"]
  skipSpaces
  rest <-
    many1
    $   (AddTag <$> addTagExpr)
    <++ (SetDue <$> dueExpr)
    <++ (AddOpt <$> optExpr)
    <++ (AddWord <$> wordExpr)
  skipSpaces
  guard $ isJust $ find notAnOpt rest
  return $ cmd : rest

一个简单的解决方案是使用Control.Monad guard
假设像isOpt :: Arg -> Bool这样的函数沿着

isOpt :: Arg -> Bool
isOpt (AddOpt _) = True
isOpt _          = False 

那么您对createExpr的定义更改为

createExpr :: ReadP [Arg]
createExpr = do
    skipSpaces
    cmd <- SetCmd <$> cmdAliasExpr ["create", "add"]
    skipSpaces
    rest <-
      many1
      $   (AddWord <$> wordExpr)
      <|> (AddTag <$> addTagExpr)
      <|> (SetDue <$> dueExpr)
      <|> (AddOpt <$> optExpr)
    guard $ at_least_one_non_optional rest
    skipSpaces
    return $ cmd : rest
  where at_least_one_non_optional = not . null . filter (not . isOpt)

当其参数为Falseguard基本上使解析器失败,更一般地说,它通过在参数为False时返回empty与任何Alternative一起使用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM