2012-11-01 100 views
4

我有兩個功能:如何避免重複的功能(IO而不是-IO版本)

trans_table :: [Char] -> [Char] -> Map.Map Char Char 
trans_table s1 s2 = Map.fromList (zip s1 s2) 

random_trans_table :: IO (Map.Map Char Char) 
random_trans_table = do 
    rawKey <- shuffle ascii 
    let zipped = zip ascii rawKey 
    let map = Map.fromList zipped 
    return map  

他們首先創建了兩個字符串地圖;第二個生成隨機地圖。 第一個返回Map.Map Char Char;第二個返回IO(Map.Map字符字符)

現在我需要從這個地圖查找價值,我已經創建了兩個功能 - 一個用於IO地圖和一個用於地圖:

translate_char :: Map.Map Char Char -> Char -> Maybe Char 
translate_char table c = Map.lookup c table 

translate_char_io :: IO (Map.Map Char Char) -> Char -> IO (Maybe Char) 
translate_char_io table c = do 
    raw_table <- table 
    let result = Map.lookup c raw_table 
    return result 

我不不喜歡它,因爲它會導致代碼重複。我已經複製了一個函數,如果我通過這種方式編碼,我將需要複製我所有的函數。

有沒有一種方法來創建函數,它將與Map和IO(Map)一起工作?

+8

你幾乎從來沒有想寫採取'IO Something'作爲輸入,除非你正在寫某種控制結構這就需要如果/當/動作運行多少次控制功能。如果你只需要一個值,你應該讓你的函數只取一個值,並在調用站點使用'do'-notation,'>> ='或類似的方法來綁定第一個動作的結果並將其傳遞給第二個。 – hammar

回答

8

do -notation,或它去糖的「綁定」運算符>>=,爲您處理此問題。

任何你可能稱爲translate_char_io的地方,都可以通過讓monad語法爲你解開你的表格來調用純函數。例如,如果你想創建一個隨機表,並期待兩個不同的人物在裏面,你可以這樣來做:

test c1 c2 = do 
    table <- random_trans_table 
    return (translate_char table c1, translate_char table c2) 
4

您可以使用liftMimport Control.Monad)寫一個轉換器:

translate_char_io table c = liftM (\table' -> translate_char table' c) table 

請注意,爲什麼您只希望table參數爲IO,但它是一個選項。翻轉參數也可以讓你擺脫liftM (translate_char c) table的內部函數。如果你想兩個參數來作爲IO行動,您還可以使用liftM2

translate_get_char = liftM2 translate_char random_trans_table getChar 

或者你可以只使用DO-符號來使用你的純函數在IO代碼,這可能是在這種情況下,最簡單的:

translateAndPrint = do 
    table <- random_trans_table 
    char <- getChar 
    putChar (translate_char table char)