您可能想要的是 ST monad 和可变向量,而不是 State Monad。
使用 IO monad 从类文件中读取字节。
bytes <- readFile myClassFile
用于对给定字节runST
运行ST
monad 计算:
let result = runST $ transform bytes
ST monad 使您可以访问可变向量,这很像 C 或 Java 数组。它们由整数索引,并具有 O(1) 查找和修改。
transform :: [Char] -> ST s [Char]
transform bytes = do
mvec <- thaw $ fromList bytes
-- you can read a value at an index
val <- read mvec 0
-- and set a value at an index
write mvec 0 (val `xor` 0xff)
-- ...
-- turn it back into a list of bytes
vec <- freeze mvec
return $ toList vec
因此,只需将 传递mvec
给您的所有函数(必须返回 ST 操作),您就可以对字节执行任何操作。
如果您不想费心将其作为参数传递,请考虑使用ReaderT
monad 转换以使mvec
所有代码都隐式可用。
transform bytes = do
-- ...
runReaderT other mvec
--- ...
other :: ReaderT (MVector s Char) (ST s) String
other = do
-- ...
-- grab the mvec when you need it
mvec <- ask
val <- lift $ read mvec 77
lift $ write mvec 77 (val * 363 - 28)
-- ...
return "Hi!"
当然,这一切都假设您需要随机访问字节。如果你不......那么你可能不需要一个MVector
.
例如,如果您需要做的只是替换0xDEADBEEF
with的每个实例0xCAFEBABE
,您可以只使用列表,不需要 ST monad:
let newBytes = intsToBytes . map (\i -> if i == 0xDEADBEEF then 0xCAFEBABE else i) $ bytesToInts bytes