我有[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 - 实现。
为什么我在三种情况下得到不同的结果?
答案 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)
失败只是因为key
是IO [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
)