【发布时间】:2014-10-08 04:26:24
【问题描述】:
我想知道关于State monad 的最佳实践是什么。我也愿意接受任何其他建议。
我有一个二进制文件要解析。它包含需要解析的不同标头才能读取完整文件。
因此可以仅使用解析中的状态来解析标头。
data ParseState = ParseState {
offset :: Int64
buffer :: B.ByteString
endianness :: Endianness
pointerSize :: MachineWord
positionStack :: [Int64]
}
这些数据随后用于State monad
type Parser a = State ParseState a
这可以完美地适应标题的解析。但只要我想解析完整的文件,我就需要来自标头的信息才能正确读取文件。
data Header = Header {
txtOffset :: Int64,
stringOffset :: Int64
}
我需要头信息才能继续解析文件。
我的想法是使用一个新的状态单子,它位于前一个单子之上。所以我有一个新的 StateT monad:
type ParserFullState a = StateT Header (State ParserState) a
因此,我可以继续使用新的状态转换器构建一整套解析器功能。
我也可以采用不同的方式,将标头添加到原始 ParseState 数据中。
在将标题添加回ParserState 时,我可以看到以下优点:
- 解析器函数的返回类型是统一的
- 无需调用
lift即可访问解析器原语。
我能看到的缺点是:
- 高级解析器和低级原语没有区别。
- 我们无法清楚地判断标头何时已完全解析,何时未完全解析。从而使解析器修改更加脆弱。
你有什么建议?我应该使用状态转换器,我应该将标头添加到原始状态还是其他任何东西?
谢谢。
【问题讨论】:
-
为什么不
data ParseState' = Initial ParseState | Later ParseState Header或其他适合您的问题的 ADT,这样您只有一个状态可以代表您的初始解析状态,然后当您需要Header时,您同时拥有 @ 987654332@ 和Header信息是分开的吗?获得标题信息后,您只需put (Later parseState header)。
标签: haskell monads state-monad