使用 >>= 和 =<< 运算符在 Haskell 中组合 IO



我正在尝试运行一个;"无限";模拟,打印每个步骤的结果。

有一个函数nextFrameR,它接受一个输入Map,并推进模拟以返回一个输出Map,还有一个render_函数,它接受输入Map,并将一些东西打印到stdout,返回输入Map(这样我就可以使用iterate或类似的东西(。

我真的很难把所有这些东西组合在一起,因为我对哈斯克尔来说相对陌生。我发现这个答案非常有趣,但由于这两个功能的结合,我不确定如何将其直接付诸实践(我曾尝试过使用liftM2iterate(。

类型签名如下:

nextFrameR :: Map -> IO Map
render_ :: Map -> IO Map -- originally Map -> IO ()

我真的不确定从这里去哪里,我可以做一些类似的事情:

(iterate (>>= nextFrameR) initialMap) :: [IO Map]

但这只是给了我一个(无限的?(帧列表(我认为(,这很好,它不允许我打印它们,因为我不知道如何组合其中的渲染功能。

iterate在非IO计算中运行得相当好,但如果您使用IO,则无法轻松利用iterate

要了解原因,请列出

(iterate (>>= nextFrameR) initialMap) :: [IO Map]

[ initialMap
, initialMap >>= nextFrameR
, initialMap >>= nextFrameR >>= nextFrameR
...

所以。。。我们怎么能利用它产生一个无限循环呢?我们不能接受不存在的";最后一个元素";。我们也不能按顺序执行该列表中的所有操作,因为这将多次运行initialMap

如果我们避免使用iterate,而采用递归等基本方法:,会更容易

loop :: Map -> IO ()
loop m = do
m' <- nextFrameR m
render_ m'       -- it looks like you want this
-- feel free to add some delay here, or some stopping condition to exit the loop
loop m'
main :: IO ()
main = do
m <- initialMap
loop m

你可以把上面的代码变成一些使用>>=的代码,但没有必要。

最后,不需要使render_返回相同的Map。您可以使该返回IO ()

如果你是一个初学者,我建议你一开始就远离";"聪明";像mapM_, traverse, for, sequence, liftM2, ap, ...这样的库函数,并学习只使用do块和递归来完成所有操作。然后,一旦了解了它的工作原理,就可以尝试利用库助手来改进代码。

相关内容

  • 没有找到相关文章

最新更新