让我们使用 type 的函数(Monad m) => a -> m a
。例如:
ghci> let f x = Just (x+1)
我希望能够多次应用它。我尝试的第一件事是
ghci> let times n f = foldr (>=>) return $ replicate n f
问题是它不适用于大型n
:
ghci> 3 `times` f $ 1
Just 4
ghci> 1000000 `times` f $ 1
Just *** Exception: stack overflow
它也不起作用:
ghci> let timesl n f = foldl' (<=<) return $ replicate n f
ghci> 3 `timesl` f $ 1
Just 4
ghci> 1000000 `timesl` f $ 1
Just *** Exception: stack overflow
实际上,有效的是使用($!)
严格运算符
ghci> let timesStrict n f = foldr1 ((>=>) . ($!)) $ replicate n f
ghci> 3 `timesStrict` f $ 1
Just 4
ghci> 10000000 `timesStrict` f $ 1
Just 10000001
有更好或更惯用的解决方案吗?或者可能是更严格的?f
如果是重量级函数,我仍然很容易发生堆栈溢出。
UPD:我发现times
用有针对性的形式写作也不能解决编写重量级单子动作的问题。这适用于 fx = Just (x+1) 但在现实世界中失败:
times f 0 a = return a
times f i a = (f $! a) >>= times f (i - 1)