zip [Char]和IO [Char]

时间:2012-10-30 05:47:49

标签: haskell

我有[Char]:

*Main> let message = "something"

我已经改组了字符串(你可以找到完整代码here):

*Main> let key = shuffle message

*Main> message
"something"

*Main> :t message
message :: [Char]

*Main> key 
"goeimntsh"

*Main> :t key
key :: IO [Char]

现在我需要从这两个字符串创建Data.Map。类似的东西:

Map.fromList(zip message key)

但我甚至不能拉[Char]和IO [Char]:

*Main> zip message key
<interactive>:1:13:
    Couldn't match expected type `[b0]' with actual type `IO [Char]'
    In the second argument of `zip', namely `key'
    In the expression: zip message key
    In an equation for `it': it = zip message key

据我所知,shuffle函数不会为同一输入返回相同的结果。所以它必须返回IO [Char]。

据我所知,我无法获得Map.Map而且我同意获得IO Map.Map。但我需要像普通字符串一样使用IO [Char]。我怎么能得到它?

感谢。

更新

感谢各位的解释。还有一些问题:

@KennyTM:

我理解'做'符号,但我需要一点时间才能获得提升M :) 但是现在还有一个问题:

*Main> let s = "abcdef"
*Main> let d = shuffle s
*Main> s
"abcdef"
*Main> d
"fedcba"
*Main> buildIOMap s d
fromList [('a','e'),('b','a'),('c','c'),('d','f'),('e','d'),('f','b')]
*Main> buildIOMap2 s d
fromList [('a','c'),('b','b'),('c','f'),('d','a'),('e','e'),('f','d')]
*Main> Map.fromList (zip "abcdef" "fedcba")
fromList [('a','f'),('b','e'),('c','d'),('d','c'),('e','b'),('f','a')]

'buildIOMap'是一种记号; 'buildIOMap2' - 是一个liftM - 实现。

为什么我在三种情况下得到不同的结果?

3 个答案:

答案 0 :(得分:4)

从GHCi提示符,您只需要

> key <- shuffle message

这会在右侧运行IO操作,并将结果存储在key中,现在只是一个纯字符串。

> :t key
key :: [Char]

另一方面,当你写了

> let key = shuffle message

你所做的只是命名动作,所以你可以多次运行它并获得不同的结果:

> :t key
key :: IO [Char]
> key
"ntimshgoe"
> key
"gimhntoes"

评估值和运行动作之间的区别在GHCi中有些模糊,因为它允许您从同一提示中执行这两个操作。但是,如果您尝试以与zip示例相同的错误方式混合它们,则会出现类型错误。

答案 1 :(得分:3)

表达式key不是[Char] - 它是IO [Char] - 即IO计算将返回[Char]。以下是如何使用shuffle函数的示例:

main = do let message = "something"
          key <- shuffle message
          -- now key is a [Char]
          let m = Data.Map.fromList (zip message key)
          print m -- ... or whatever

从某种意义上说,<-会从IO中解包IO [Char],并将返回的值放入<-左侧的变量中。

答案 2 :(得分:3)

我们可以为此制作IO功能。我们在这里使用do符号,因为它对于具有命令式语言背景的初学者更友好,但它不是最紧凑的方式。

buildIOMap message key = do
    rawKey <- key                   -- unwrap an object inside the 'do' with '<-'
    let zipped = zip message rawKey -- Then 'zip' & 'Map.fromList' can be used 
    let map = Map.fromList zipped   --   normally.
    return map                      -- Finally we re-wrap the result into IO.

我们也可以用更实用的方式解决这个问题,即改变函数本身。请注意,表达式Map.fromList (zip message key)失败只是因为keyIO [Char]而不是[Char]

如果我们可以将函数Map.fromList (zip message __)从接受[Char]转换为IO [Char],那么它也可以正常工作。这种转换称为提升,当在Haskell the Control.Monad.liftM function中执行此操作时:

liftM :: Monad m => (a -> r) -> (m a -> m r)

这将使用1个纯参数的函数并返回1个纯参数,并给出一个带有1个monadic参数的函数并返回1个monadic参数。

这里我们的纯函数是:

\x -> Map.fromList (zip message x)

所以我们也可以写:

buildIOMap message = liftM (\x -> Map.fromList (zip message x))

(注意:表示上述内容的更紧凑的方法是buildIOMap message = liftM $ Map.fromList . zip message