【问题标题】:Monadic parsing of binary data in HaskellHaskell中二进制数据的一元解析
【发布时间】:2016-03-21 11:44:12
【问题描述】:

我对 Haskell 很陌生,我的第一个项目是解析捕获的 WLAN 数据包。解析此类数据包的常见模式是标头字段将定义剩余字节的结构。作为一个通用示例,数据包可以这样格式化:

header + [payload A | payload B | ..] 

标头中的标志字段(可以是位图)指定数据包中包含哪些有效负载。有关此格式的具体示例,请查看radiotap

A similar thread 建议只使用一系列parse 操作,如下所示:

parseAll = do
    hdr <- parseHeader
    pa <- parsePayloadA
    pb <- parsePayloadB

但它似乎不适用于我的情况,因为有效载荷 AB 的存在是由标头定义的。换言之,数据解析的控制流需要遵循先验的解析结果。我想了解,如果有一种通用的方法来解析这种模式的二进制数据?

【问题讨论】:

    标签: haskell monads


    【解决方案1】:

    注意parseAll 使用某种monadic 解析器库(从do 表示法和绑定的使用中可以看出)。 monad 的强大之处在于您对parsePayloadAparsePayloadB 的选择可以依赖于hdr:您拥有Haskell 的全部功能来检查hdr

    所以基本上你可以做类似的事情

    parseAll = do
        hdr <- parseHeader
        payload <- case somethingInTheHdr hdr of
           ThisIsAnA -> do
             a <- parsePayloadA
             return (PayloadA a)
           ThisIsAB -> do
             b <- parsePayloadB
             return (PayloadB b)
        -- can use body here, e.g.
        return (Packet hdr payload)
    

    您之所以拥有这种能力,是因为在单子绑定类型中:

    (>>=) :: m a -> (a -> m b) -> m b
    

    a -&gt; m b 中的箭头是真正的 Haskell 函数箭头,为您提供所需的所有功能。

    【讨论】:

    • 谢谢。在这种情况下,“有效载荷”的类型是什么?
    • 这是假设你有两个可能的有效载荷,data Payload = PayloadA A | PayloadB B
    【解决方案2】:

    这正是 Monad 接口的目的:编码计算对先前计算结果的依赖性。

    在您的情况下,它将类似于以下内容:

    parseAll = do
      shouldThePayloadABeParsed <- parseHeader
      if shouldThePayloadABeParsed
        then do
          pa <- parsePayloadA
          ...
        else do
          pb <- parsePayloadB
          ...
    

    出于您的目的,我建议您阅读 "Taste of State: Parsers are Easy" 帖子以了解这种解析在 Haskell 中的工作原理,以及用于解析的 "binary-parser" 包。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-11-23
      • 2014-11-12
      • 1970-01-01
      • 1970-01-01
      • 2011-10-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多