【发布时间】:2011-01-15 06:17:16
【问题描述】:
让我们使用(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 以一种有针对性的形式也不能解决编写重量级单子动作的问题。这适用于 f x = Just (x+1) 但在现实世界中失败:
times f 0 a = return a
times f i a = (f $! a) >>= times f (i - 1)
【问题讨论】:
标签: haskell lazy-evaluation monads reduce