1

Haskell で Java クラス ファイルを取り込んで、同一であるがいくつかの変更を含む別のクラス ファイルを作成する関数を作成しています。このためには、少なくともクラス ファイルのすべてのバイトを保持する [Word8] を保持する状態モナドが絶対に必要だと感じています。しかし、Haskell のステート モナドに関する調査をすべて行った後でも、これを行う方法を理解するのにまだ苦労しています。誰かが私を正しい方向に向けることができますか? すべての関数の範囲内にあり、関数から変更できる [Word8] (または任意のデータ型) を使用できるようにしたいと考えています。これには state<-get ... put newstate のようなものを使用する必要があることを理解しています

しかし、モナドなどの定義をどこから始めるべきか本当にわかりません。

よろしくお願いします!

4

2 に答える 2

7

モナドが必要かどうかはわかりません。State行いたい変更の種類に応じて、変更したいデータを変更したいすべての関数に渡すことができます。通常、状態の​​変更に加えStateて値を生成する状況、つまり のような関数をたくさん書いている場合に使用します。s -> (s,a)

最初に通常の機能のアプローチを試してください。State魔法ではなく、特定の種類のコードをすばやく、簡潔に、正確に記述しやすくするだけです。それを使ってできることはすべて、それがなくてもできます。少し面倒です。

于 2012-04-20T00:10:25.077 に答える
2

おそらく、State モナドの代わりに、ST モナドと変更可能なベクトルが必要です。

IO モナドを使用して、クラス ファイルからバイトを読み込みます。

bytes <- readFile myClassFile

指定されたバイトでモナド計算runSTを実行するために使用します。ST

let result = runST $ transform bytes

ST モナドは、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

そのため、すべての関数 (ST アクションを返す必要があります) に を渡すだけでmvec、バイトに対してやりたいことが何でもできるようになります。

わざわざ引数として渡したくない場合は、ReaderTモナド変換を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 モナドは必要ありません。

 let newBytes = intsToBytes . map (\i -> if i == 0xDEADBEEF then 0xCAFEBABE else i) $ bytesToInts bytes
于 2012-04-19T22:58:37.140 に答える