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
然而,它似乎不能应用于我的情况,因为有效负载 A
和 B
的存在是由 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 的强大之处在于你选择 parsePayloadA
和 parsePayloadB
可以取决于 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功能箭头,为您提供所需的一切力量。
我是 Haskell 的新手,我的第一个项目是解析捕获的 WLAN 数据包。解析此类数据包的常见模式是 header 字段将定义剩余字节的结构。作为一个通用的例子,一个数据包可以这样格式化:
header + [payload A | payload B | ..]
其中 header 中的标志字段(可以是位图)指定数据包中包含哪些有效载荷。有关此格式的具体示例,请查看 radiotap.
A similar thread 建议只使用一系列 parse
操作,如下所示:
parseAll = do
hdr <- parseHeader
pa <- parsePayloadA
pb <- parsePayloadB
然而,它似乎不能应用于我的情况,因为有效负载 A
和 B
的存在是由 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 的强大之处在于你选择 parsePayloadA
和 parsePayloadB
可以取决于 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功能箭头,为您提供所需的一切力量。