我想知道什么可以被视为关于State
monad的最佳做法。我也对任何其他建议持开放态度。
我有一个要解析的二进制文件。它包含需要解析的不同标头,以便能够读取整个文件。
因此,只能使用解析中的State来解析头文件。
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
}
我需要标头信息才能继续解析文件。
我的想法是使用一个位于前一个状态之上的新状态monad。所以我有一个新的StateT monad:
type ParserFullState a = StateT Header (State ParserState) a
因此,我可以使用新的状态转换器继续构建一整套解析器函数。
我也可以采用不同的方式将标题添加到原始的ParseState
数据中。
我可以看到将标题添加回ParserState
的优点如下:
lift
来访问解析器原语。我能看到的缺点是:
你的建议是什么?我应该使用状态转换器吗?我应该将标头添加到原始状态还是其他任何地方?
感谢。
答案 0 :(得分:7)
一般来说,我建议不要使用多层State
(或任何变压器)。变形金刚很棒,但在较粗的集群中,它们确实会让人感到困惑,特别是当类型系统无法正确决定使用哪个MonadState
时。
尽管如此,在你的具体情况下,另一个变换器实际上是一个好主意,但不是StateT
:在进一步解析文件时标题信息不应该改变,所以它应该只是一个ReaderT
,不应该吗?
type ParserFullState = ReaderT Header (State ParserState)
type ParserFullState = RSS Header () ParserState