通过按广度优先顺序列出目录的所有内容会导致效率低下的问题,我了解到效率低下是由于递归 monad 函数的奇怪行为。
尝试
sequence $ map return [1..]::[[Int]]
sequence $ map return [1..]::Maybe [Int]
而ghci会陷入无休止的计算。
如果我们以更易读的形式重写序列函数,如下所示:
sequence' [] = return []
sequence' (m:ms) = do {x<-m; xs<-sequence' ms; return (x:xs)}
并尝试:
sequence' $ map return [1..]::[[Int]]
sequence' $ map return [1..]::Maybe [Int]
我们得到同样的情况,一个无限循环。
尝试有限列表
sequence' $ map return [1..]::Maybe [Int]
Just [1,2,3,4..]
经过长时间的等待,它会弹出预期的结果。
通过我们的尝试,我们可以得出结论,虽然sequence'的定义看起来很懒惰,但它是严格的,必须在打印sequence'的结果之前把所有的数字都弄出来。
不仅仅是序列',如果我们定义一个函数
iterateM:: Monad m => (a -> m a) -> a -> m [a]
iterateM f x = (f x) >>= iterateM0 f >>= return.(x:)
并尝试
iterateM (>>=(+1)) 0
然后发生无休止的计算。
众所周知,非monadic iterate的定义和上面的iterateM一样,但是为什么iterate是lazy的,iterateM是strict的。从上面我们可以看出,iterateM和sequence'都是递归monadic函数。递归monadic函数有什么奇怪的吗