4

我有两个功能:

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.Map Char Char;第二个返回 IO (Map.Map Char Char)

现在我需要从这个 Map 中查找值,并且我创建了两个函数 - 一个用于 IO Map,另一个用于 Map:

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) 一起使用的函数?

4

2 回答 2

8

do-notation 或>>=它脱糖的“绑定”运算符会为您处理这个问题。

任何你想调用的地方translate_char_io,你都可以通过让 monad 语法为你解开你的表来调用纯函数。例如,如果你想创建一个随机表并在其中查找两个不同的字符,你可以这样做:

test c1 c2 = do
    table <- random_trans_table
    return (translate_char table c1, translate_char table c2)
于 2012-11-01T06:03:00.837 回答
4

您可以使用liftM ( import 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-notation 在你的 IO 代码中使用你的纯函数,在这种情况下这可能是最简单的:

translateAndPrint = do
    table <- random_trans_table
    char <- getChar
    putChar (translate_char table char)
于 2012-11-01T06:13:44.467 回答