迭代+永远= iterateM? 重复与反馈的作用(iterate + forever = it

2019-09-17 14:01发布

我想永远重复一个IO动作,它们只是一个执行到下的结果。 事情是这样的:

-- poorly named
iterateM :: Monad m => (a -> m a) -> a -> m b
iterateM f a = f a >>= iterateM f

Hoogle似乎并没有帮助我,但我看到很多看起来诱人接近我想要的功能,但没有人可以走到一起,是它到底。

Answer 1:

你说得对,我不知道这个特别的循环方式实现的地方。 你的实现看起来不错; 为什么不提交它作为一个补丁的单子,循环包装?



Answer 2:

好吧,我会期待一个iterateM组合子有这种类型的签名:

iterateM :: (Monad m) => (a -> m a) -> a -> m [a]

当然,这并不是一个非常有用的组合子,因为你不能提取结果在大多数单子。 一个更明智的名义去与你的组合子将是基地命名标准iterateM_

iterateM_ :: (Monad m) => (a -> m a) -> a -> m b
iterateM_ f = fix $ \again x -> f x >>= again

这种组合子可能是有用的:

countFrom :: (Enum a) => a -> IO b
countFrom = iterateM_ (\x -> succ x <$ print x)

但是,为了简单起见,我只想去与fix或明确的递归。 在明确递归代码不是或更长的时间要少得多可读。

countFrom :: (Enum a) => a -> IO b
countFrom = fix (\again x -> print x >> again (succ x))


Answer 3:

我相信你不会看到这个标准库的原因是因为它永远不会终止。 在迭代函数可以利用惰性列表,让您使用指定终止take结果列表功能。 在这里,你的结果是一元,所以这是不可能的。

显然,你的精神理念可以做到的。 它只是看起来有点不同:

iterateM :: Monad m => Int -> (a -> m a) -> a -> m a
iterateM 0 _ a = return a
iterateM n f a = f a >>= iterateM (n-1) f


Answer 4:

这其实可以写成方面forever使用StateT

import Control.Monad.Trans.State
import Control.Monad.Trans.Class (lift)
import Control.Monad (forever)

iterateM :: Monad m => (a -> m a) -> a -> m b
iterateM f = evalStateT $ forever $ get >>= lift . f >>= put


文章来源: iterate + forever = iterateM? Repeating an action with feedback