2012-04-19 84 views
1

我正在Haskell中編寫一個函數,它接收一個Java類文件,並寫入另一個相同但包含一些修改的類文件。爲此,我覺得我絕對需要一個狀態monad來至少保存包含類文件所有字節的[Word8]。然而,在對Haskell的State Monads進行的所有研究之後,我仍然無法弄清楚如何做到這一點。任何人都可以將我指向正確的方向嗎?我希望能夠有一個[Word8](或者你知道的,任何數據類型),它是在所有功能的範圍內,並且我可以從函數中修改。我理解這涉及使用類似 狀態< -get ... 放newstateHaskell中的State Monads

,但我真的不知道從哪裏開始的定義單子和諸如此類的東西。

非常感謝!

+0

http:// stackoverflow。com/questions/10230562/confusion-over-the-state-monad-code-on-learn-you-a-haskell – 2012-04-19 21:30:05

+0

你會對字節做什麼樣的轉換?你插入和刪除塊?你需要隨機訪問?在擔心需要使用哪個monad之前,首先要弄清楚您需要哪種數據結構。這更重要。 – rampion 2012-04-20 11:02:23

+0

此外,我猜測[這個問題]的答案(http://stackoverflow.com/questions/10253474/inject-a-function-into-a-java-class-file-using-haskell)將是對你有用。 – rampion 2012-04-20 21:44:57

回答

2

你可能想要的是ST monad和mutable vector,而不是State Monad。

使用IO monad從類文件中讀取字節。

bytes <- readFile myClassFile 

使用runST對給定的字節運行ST單子計算:

let result = runST $ transform bytes 

的ST單子,您可以訪問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

例如,如果你需要做的就是0xCAFEBABE取代0xDEADBEEF每一個實例,你可以只使用列表,無需ST單子:

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

可變向量讓你讀寫O(1),但插入和刪除是O(n),所以我不確定這是否是最好的選擇,除非你確定你沒有改變類文件中的字節數。 – 2012-04-20 05:44:17

+0

@丹伯頓:你知道,我甚至不認爲Pha3drus可能會這樣做。好決定! – rampion 2012-04-20 11:00:53

7

我不知道你做一個State單子。根據您想要修改的修改類型,您可以使用將您想要修改的數據傳遞給每個要修改它的功能。 State通常用於產生值另外以修改狀態的情況,即當您正在編寫看起來像s -> (s,a)的許多函數時。

先試試一下正常功能的方法。 State並不神奇,它只是使某些類型的代碼更容易快速,簡潔和正確地編寫。你可以用它做的一切你也可以沒有它,它只是更乏味。

+0

謝謝,我最終只使用了許多類似於模擬狀態更改的正常函數。如果有人很好奇,該項目涉及讀取類文件,將其分離爲各個部分,並向方法中添加代碼以在輸入方法時打印出方法的名稱。再次感謝! – Pha3drus 2012-04-21 13:07:22