Haskell 为什么我的函数不能处理无限列表?
我试图学习haskell并实现一个函数Haskell 为什么我的函数不能处理无限列表?,haskell,lazy-evaluation,Haskell,Lazy Evaluation,我试图学习haskell并实现一个函数conseq,该函数将返回大小为n的连续元素列表 conseq :: Int -> [Int] -> [[Int]] conseq n x | n == length(x) = [x] | n > length(x) = [x] | otherwise = [take n x] ++ (conseq n (drop 1 x)) 这是正确的 > take 5 $ conseq 2 [1..10]
conseq
,该函数将返回大小为n的连续元素列表
conseq :: Int -> [Int] -> [[Int]]
conseq n x
| n == length(x) = [x]
| n > length(x) = [x]
| otherwise = [take n x] ++ (conseq n (drop 1 x))
这是正确的
> take 5 $ conseq 2 [1..10]
[[1,2],[2,3],[3,4],[4,5],[5,6]]
但是,如果我通过[1..]
而不是[1..10]
,程序就会陷入无限循环
据我所知,haskell有懒惰的评估,所以我应该仍然能够得到相同的结果,对吗?它是长度
?当长度大于n
时,前两个条件是否应立即计算为false
我误解了什么?函数做的第一件事是计算
长度(x)
,这样它就知道是否应该返回[x]
,[x]
,或者[take nx]++(conseq n(drop 1x))
length
统计列表中的元素数-所有元素。如果你要求一个无限列表的长度,它永远不会完成计数。使用长度
不是一个好主意的主要原因之一是,当它必须在一个无限列表上求值时,它将陷入无限循环
但好消息是,我们不需要长度
。这也会使时间复杂性变得更糟。我们可以使用两个枚举数,一个比另一个提前n-1个位置。如果此枚举数到达列表的末尾,则我们知道第一个枚举数仍有n-1个元素,因此我们可以停止生成值:
conseq :: Int -> [a] -> [[a]]
conseq n ys = go (drop (n-1) ys) ys
where go [] _ = []
go (_:as) ba@(~(_:bs)) = take n ba : go as bs
什么是
length(x)
,其中x==[1..]
?是不是length
没有被惰性地评估?那么,你如何惰性地评估它呢?如果不知道此列表的长度,则无法继续执行,因此必须立即计算它。我不完全确定though@TessaAltman:所有内容都是惰性评估的,但当需要时,会对其进行评估,然后length
陷入无限循环。如果length
返回类似于Peano数的值,并且如果对Peano数的比较是延迟实现的,则可以使用n>length x
避免无限循环。但是使用Int
和内置的length
,情况就不是这样了。~ba@(:bs)
到底在做什么?我假设(:bs)
正在删除列表的标题,然后将bs
设置为正常模式匹配的其余部分,但我没有遇到~
或@
符号before@mattematt:@
是as模式(),~
用于无可辩驳的模式
Prelude> conseq 3 [1 ..]
[[1,2,3],[2,3,4],[3,4,5],[4,5,6],[5,6,7],[6,7,8],[7,8,9],[8,9,10],[9,10,11],[10,11,12],[11,12,13],[12,13,14],[13,14,15],[14,15,16],[15,16,17],[16,17,18],[17,18,19],[18,19,20],[19,20,21],[20,21,22],[21,22,23],[22,23,24],[23,24,25],[24,25,26],[25,26,27],…
Prelude> conseq 3 [1 .. 4]
[[1,2,3],[2,3,4]]