Haskell 中二进制数据的 Monadic 解析

Monadic parsing of binary data in Haskell

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

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

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

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

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

然而,它似乎不能应用于我的情况,因为有效负载 AB 的存在是由 header 定义的。也就是说,数据解析的控制流程需要遵循一个先验的解析结果。我想知道是否有一种通用的方法可以用这种模式解析二进制数据?

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

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

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

出于您的目的,我建议阅读 "Taste of State: Parsers are Easy" post to get an understanding of how this kind of parsing works in Haskell, and the "binary-parser" 包来进行解析。

注意 parseAll 使用某种 monadic 解析器库(从 do 符号和绑定的使用可以看出)。 monads 的强大之处在于你选择 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)

你有这个能力是因为在 monadic bind 类型中:

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

a -> m b中的箭头是真正的Haskell功能箭头,为您提供所需的一切力量。