您可能想要的是 ST monad 和可变向量,而不是 State Monad。
使用 IO monad 从类文件中读取字节。
bytes <- readFile myClassFile
使用runST 对给定字节运行ST monad 计算:
let result = runST $ transform bytes
ST monad 让您可以访问mutable vectors,这很像 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 的每个实例替换为 0xCAFEBABE,您可以只使用列表,不需要 ST monad:
let newBytes = intsToBytes . map (\i -> if i == 0xDEADBEEF then 0xCAFEBABE else i) $ bytesToInts bytes