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