尝试简化Attoparsec解析器中IO Bool的检查

时间:2012-12-04 21:13:26

标签: haskell attoparsec

我正在尝试简化下面的代码,它是网络数据包的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,如果存在有效的JSON有效负载,则返回Just A.Value;如果存在无效的有效负载,则返回解析器失败。< / p>

这是最终创建的Packet记录:

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

2 个答案:

答案 0 :(得分:3)

你做了很多你不需要做的工作。首先,检查您是否在数据的末尾,如果不能解决问题,则返回Nothing。这不是必需的,因为如果你最后,任何需要内容的解析器都会失败,使用maybeResult会将失败转换为Nothing

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

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

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

如果您愿意,可以将其用作maybeResult $ parse payload input来获取Maybe A.Value,而Parser不会另外包含在maybeResult中。如果您不应用Fail,则可以对返回的Result进行模式匹配,以便单独处理PartialSuccess成功和maybePayload :: Parser (Maybe A.Value) maybePayload = char ':' *> (Just <$> A.json) <|> (Nothing <$ endOfInput)


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

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

所以我们得到:

<$>

我使用了来自<$的{​​{1}}和Control.Applicative,或者如果您愿意,则来自Data.Functor

<$>fmap的中缀版本,因此Just <$> A.json执行A.json并将Just中的任何输出换行。

<$fmap.const,因此将()替换为endOfInput Nothing

答案 1 :(得分: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