我正在尝试简化下面的代码,它是网络数据包的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
}
答案 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进行模式匹配,以便单独处理Partial
,Success
成功和maybePayload :: Parser (Maybe A.Value)
maybePayload = char ':' *> (Just <$> A.json)
<|> (Nothing <$ endOfInput)
。
编辑:好的,现在更清楚,谢谢:
所以我们得到:
<$>
我使用了来自<$
的{{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