有人指出这是foldM的情况吗?作为可能的重复.现在,我有一个强烈的意见,即可以用相同答案回答的两个问题不一定是重复的!"什么是1 - 2"和"什么是我^ 2"都产生"-1",但不是,它们不是重复的问题.我的问题(已经回答,类似)是关于"函数是否iterateM存在于Haskell标准库中",而不是"如何实现链式monad操作".
当我写一些项目时,我发现自己编写了这个组合器:
repeatM :: Monad m => Int -> (a -> m a) -> a -> m a
repeatM 0 _ a = return a
repeatM n f a = (repeatM (n-1) f) =<< f a
Run Code Online (Sandbox Code Playgroud)
它只执行monadic动作n时间,将前一个结果输入下一个动作.我尝试了一些hoogle搜索和一些谷歌搜索,并没有找到"标准"Haskell附带的任何东西.是否有预定义的正式功能?
Eri*_*ikR 10
你可以使用foldM,例如:
import Control.Monad
f a = do print a; return (a+2)
repeatM n f a0 = foldM (\a _ -> f a) a0 [1..n]
test = repeatM 5 f 3
-- output: 3 5 7 9 11
Run Code Online (Sandbox Code Playgroud)
卡斯滕提到 replicate,这并不是一个糟糕的想法.
import Control.Monad
repeatM n f = foldr (>=>) pure (replicate n f)
Run Code Online (Sandbox Code Playgroud)
这背后的想法是,对于任何monad m,类型的函数a -> m b形成Kleisli类别m,带有标识箭头
pure :: a -> m a
Run Code Online (Sandbox Code Playgroud)
(也叫return)
和作曲家
(<=<) :: (b -> m c) -> (a -> m b) -> a -> m c
f <=< g = \a -> f =<< g a
Run Code Online (Sandbox Code Playgroud)
由于实际上是处理类型的函数a -> m a,我们真的在看一个Kleisli类别的monoid,所以我们可以考虑折叠这些箭头的列表.
上面的代码所做的是将合成运算符折叠成一个n副本列表,f像往常一样以身份完成.翻转合成操作符实际上使我们进入了双重类别; 对于许多常见的单子,x >=> y >=> z >=> w比效率更高w <=< z <=< y <=< x; 因为在这种情况下所有箭头都是相同的,所以我们似乎也可以.请注意,对于懒惰状态monad以及可能还有读取器monad,使用未翻译的<=<运算符可能更好; >=>一般将更好的IO,ST s和平时的严格的国家.
注意:我不是类别理论家,所以上面的解释可能有错误.