0

我正在尝试简化以下代码,该代码是网络数据包的 attoparsec 解析器的一部分,但我不知道如何做这件事。

它首先调用以atEnd :: IO Bool确定是否还有更多要解析的内容。我找不到atEnd比从 IO 解包然后在 if 语句中使用它更好的使用方法,但似乎必须有一种更简单的方法来检查 monad 中的 bool。这是代码:

maybePayload :: Parser (Maybe A.Value)
maybePayload = do
    e <- atEnd
    if e then return Nothing
    else do
        payload' <- char ':' *> takeByteString
        maybe mzero (return . Just) (maybeResult $ parse A.json payload') 

目的是在Nothing没有有效负载的情况下返回,Just A.Value如果有有效的 JSON 有效负载则返回,如果有无效的有效负载则解析器失败。

这是最终创建的数据包记录:

data Packet = Packet
    { pID       :: Integer
    , pEndpoint :: String
    , pPayload  :: Maybe A.Value
    }
4

2 回答 2

3

你正在做很多你不需要做的工作。首先,您检查您是否处于数据的末尾,Nothing如果不成功则返回。这不是必需的,因为如果你在最后,任何需要内容的解析器都会失败,而 usingmaybeResult会将失败变成Nothing.

您的解析器唯一失败的情况是输入具有不以字符开头的数据的情况:,其余时间它成功,即使那是通过返回Nothing

唯一实际进行的解析是检查:然后使用A.json. 我认为您正在尝试在一个解析器中编写整个程序,而您应该自己进行解析,然后根据需要调用它。无需检查数据是否结束,或确保您获得全部内容——这些都是免费内置在解析器中的。一旦你摆脱了所有不必要的检查,你就会得到

payload :: Parser A.Value
payload = char ':' *> A.json

如果你愿意,你可以使用它maybeResult $ parse payload input来获得一个Maybe A.Value没有额外包装在Parser. 如果不申请maybeResult,可以对返回的Result进行模式匹配,分别处理Failure、Partialsuccess和Success.


编辑:好的,现在更清楚了,谢谢:

  • (如果冒号后跟无效的 json,则失败)
  • 如果有一个冒号后跟有效的 json,则成功,将其包装在 Just
  • 如果只有输入结束,成功,返回Nothing

所以我们得到:

maybePayload :: Parser (Maybe A.Value)
maybePayload = char ':' *> (Just <$> A.json)
            <|> (Nothing <$ endOfInput)

我用过<$>and <$from Control.Applicative,或者如果你喜欢的话, from Data.Functor

<$>是 的中缀版本fmap,因此Just <$> A.json也是如此,A.json并将任何输出包装在Just.

<$is fmap.constso 将()fromendOfInput替换为Nothing.

于 2012-12-04T23:22:47.890 回答
0

当解析器 monad 已经具有内置的失败概念时,为什么需要在 Maybe 中编码失败?以这种方式使用 Maybe 的问题是解析器无法回溯。

您可以尝试这样的事情(我没有尝试过类型检查),然后option在调用者中使用:

payload :: Parser Value
payload = do
  payload' <- char ':' *> takeByteString
  let res = parse A.json payload'
  case res of
    Error msg -> fail msg
    Success a -> return a
于 2012-12-04T22:19:09.803 回答