正如在我之前的问题中,我正在尝试将Data.Binary.Put monad包装到另一个monad中,以便稍后我可以问它"它要写多少字节"或"文件中的当前位置是什么"等问题.
之前,我认为理解为什么它在使用一个简单的(IdentityT?)包装器时会泄漏内存会导致我解决我的问题.但即使你们帮我解决了这个简单的包装器的问题,用StateT或WriterT之类的东西包装它仍然会消耗太多的内存(并且通常会崩溃).
例如,这是我试图包装它的一种方式,它为大输入泄漏内存:
type Out = StateT Integer P.PutM () writeToFile :: String -> Out -> IO () writeToFile path out = BL.writeFile path $ P.runPut $ do runStateT out 0 return ()
这是一个更完整的代码示例,演示了该问题.
我想知道的是:
对于我的第二个问题,我想我应该更详细地解释一下我打算在磁盘上查看数据:它基本上是一个树结构,其中树的每个节点都表示为它的子节点的偏移表(加上一些附加数据).因此,要计算第n个孩子到偏移表中的偏移量,我需要知道子项0到n-1的大小加上当前偏移量(为了简化事情,假设每个节点都有固定数量的子节点).
谢谢你的期待.
更新:感谢nominolo我现在可以创建一个包裹Data.Binary.Put的monad,跟踪当前偏移并几乎不使用任何内存.这是通过放弃使用StateT转换器来支持使用Continuations的不同状态线程机制来完成的.
像这样:
type Offset = Int newtype MyPut a = MyPut { unS :: forall r . (Offset -> a -> P.PutM r) -> Offset -> P.PutM r } instance Monad MyPut where return a = MyPut …
我正在尝试将Data.Binary.PutM monad修改为monad转换器.所以我从changin的定义开始
newtype PutM a = Put { unPut :: PairS a }
Run Code Online (Sandbox Code Playgroud)
至
newtype PutM a = Put { unPut :: Identity (PairS a) }
Run Code Online (Sandbox Code Playgroud)
然后我当然改变了return和>> =函数的实现:
从:
return a = Put $ PairS a mempty
{-# INLINE return #-}
m >>= k = Put $
let PairS a w = unPut m
PairS b w1 = unPut (k a)
in PairS b (w `mappend` w1)
{-# INLINE (>>=) #-}
m >> k = Put …
Run Code Online (Sandbox Code Playgroud)