这在tryhaskell.org上进入无限循环.我不知道为什么.
last $ filter (<100) $ [2..] >>= (\a -> if 0 == (length $ filter (== 0) $ map (mod a) $ [2..a-1]) then (return a) else [])
Run Code Online (Sandbox Code Playgroud)
这并不是拒绝懒惰,只是没有办法让它知道在你获得所有素数<100之后,就没有了.
如果序列看起来怎么样
1,2,... 99,100,101,102,5,103 ......
换句话说,last无法预测未来.哦,我多么希望.
让我们把事情分开,从内到外.从这开始:
last $ filter (<100) $ [2..] >>= (\a -> if 0 == (length $ filter (== 0) $ map (mod a) $ [2..a-1]) then (return a) else [])
Run Code Online (Sandbox Code Playgroud)
首先考虑map (mod a) [2..a-1].这只是一个有限列表的转换,所以这里没有问题,我们将从这里忽略它,放在[..]它的位置.因为我们只关心终止,所以任何有限列表都与另一个有关.
同样如此filter (== 0) [...].这只能使列表更短,所以我们最终可能会得到一个空列表,但肯定是有限的.所以也要忽略它.现在考虑 - length [..]我们知道列表是有限的,所以这将终止正常,给出一些0或更多的答案.我们将忽略具体的答案并?取而代之.到目前为止仍然很好.
拉姆达\a -> if 0 == ? then return a else []是使用return列表中的单子,所以这个替换a用两种[a]或者[],这是偶然等同Maybe,但那是另一回事.同样,我们知道这很有用,所以我们忽略了细节和使用\a -> [a?].
monadic绑定[2..] >>= \a -> [a?]更有趣.(>>=)这是concatMap,第一个参数是无限列表.将每个元素映射到单个列表并连接显然不会改变任何内容,而映射到空列表会删除一个元素,所以这基本上就是这样filter.然而,事情并不是那么简单,因为我们正在过滤无限列表而没有明确保证任何事情都会通过过滤器.如果你这样做filter (const False) [0..],"结果"将没有元素,但计算永远不会完成; 将[]在输出filter来自查找输入列表的末尾,这也没有,因为它永远不会找到一个第一要素,结果是刚_|_.
所以事情已经成问题了.下一部分filter (<100)会让事情变得更糟 - 我们从严格增加的列表中过滤元素,然后根据某些值过滤它,所以通过上面的参数,如果我们100在结果中过去,计算将会挂起.
最后的侮辱是last- 所讨论的列表仍然是无限的,但在某些时候会分歧而不是产生更多的元素,所以当我们要求最后一个元素时,我们可以看到它将因多种原因而无法终止!
你想在这里做的是,首先,应用你的知识,列表严格增加,而不是过滤列表,只需将其前缀添加到所需的点 - 例如,takeWhile (<100)而不是filter (< 100).请注意,如果结果中没有大于100的元素,这仍然会发散,因为takeWhile不知道何时停止.