简体   繁体   English

哈斯克尔州莫纳德斯

[英]State Monads in Haskell

I am writing a function in Haskell that takes in a Java class file, and writes another class file that is identical but contains some modifications. 我正在Haskell中编写一个函数,该函数接收Java类文件,并编写另一个相同但包含一些修改的类文件。 For this, I feel that I definitely need a state monad to at least hold the [Word8] that holds all of the bytes of the class file. 为此,我觉得我绝对需要一个状态monad,以至少保留用于保存类文件所有字节的[Word8]。 However, after all of my research on State Monads in Haskell, I am still having trouble figuring out how to do this. 但是,在对Haskell的State Monads进行所有研究之后,我仍然很难弄清楚该如何做。 Can anyone point me in the right direction? 谁能指出我正确的方向? I would like to be able to have a [Word8] (or you know, any data type) that is in scope for all of the functions and that I can modify from functions. 我希望能够有一个[Word8](或您知道的任何数据类型),它在所有函数的范围内,并且可以从函数中进行修改。 I understand this involves using something like state<-get ... put newstate 我了解这涉及使用诸如state <-get ... put newstate之类的东西

but I really don't know where to start with defining the monad and whatnot. 但我真的不知道从定义monad和诸如此类的地方开始。

Thanks so much in advance! 非常感谢!

I'm not sure you do want a State monad. 我不确定您是否想要State monad。 Depending on what kind of modifications you want to make, you are allowed to just pass the data you want to modify to every function that wants to modify it. 根据什么样的你想修改的,你允许只传递要修改每一个想要修改它的功能的数据。 State is usually for situations where you are producing a value in addition to modifying state, ie when you are writing a lot of functions that look like s -> (s,a) . State通常用于修改状态还产生值的情况,即编写许多类似于s -> (s,a)的函数时。

Try just a normal-function approach first. 首先尝试仅使用正常功能的方法。 State isn't magic, it just makes certain types of code easier to write quickly, concisely, and correctly. State不是魔术,它只是使某些类型的代码更容易快速,简洁和正确地编写。 Everything you can do with it you can also do without it, it's just a bit more tedious. 您可以使用它执行的所有操作,也可以不使用它执行操作,这只会更加乏味。

What you probably want, instead of the State Monad, is the ST monad and mutable vectors. 您可能想要的是ST monad和可变矢量,而不是State Monad。

Use the IO monad to read the bytes in from the class file. 使用IO monad从类文件中读取字节。

bytes <- readFile myClassFile

use runST to run your ST monad calculation on the given bytes: 使用runST在给定的字节上运行ST monad计算:

let result = runST $ transform bytes

The ST monad gives you access to mutable vectors , which are a lot like C or Java arrays. ST monad使您可以访问可变向量 ,该向量很像C或Java数组。 They're indexed by integers, and have O(1) lookup and modify. 它们由整数索引,并具有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

So just pass around the mvec to all your functions (which must return a ST action), and you'll be able to do whatever you want to the bytes. 因此,只需将mvec传递给所有函数(必须返回ST动作),就可以对字节执行任何操作。

If you don't want to bother with passing it as an argument, consider using the ReaderT monad transform to make the mvec implicitily available to all your code. 如果您不希望将其作为参数传递,请考虑使用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!"

Of course, this is all assuming you need random access to the bytes. 当然,所有这些都假设您需要随机访问这些字节。 If you don't... then you probably don't need an MVector . 如果不这样做,那么您可能不需要MVector

For example, if all you need to do is replace every instance of 0xDEADBEEF with 0xCAFEBABE , you could just use lists, no ST monad required: 例如,如果您需要做的就是将0xDEADBEEF每个实例替换为0xCAFEBABE ,则可以只使用列表,而无需ST monad:

 let newBytes = intsToBytes . map (\i -> if i == 0xDEADBEEF then 0xCAFEBABE else i) $ bytesToInts bytes

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM