我试图理解在无限列表上应用过滤器的结果。我需要一个解释来了解幕后发生的事情。
let nums = Seq.initInfinite id |> Seq.filter ((>) 0);;
nums |> Seq.take 0;; // of course, this works
nums |> Seq.take 1;; // this overflows
在我的阅读中,第一行意味着“在零处开始无限序列并过滤掉大于零的所有值(例如1,2,3等......)”。因此,获取零值将返回空集。好的,有道理。但是,如果我们取一个值,并且该值为零,显然不大于零,为什么溢出?
进一步尝试:
let nums = Seq.initInfinite (fun i -> i - 1) |> Seq.filter ((>) 0);;
nums |> Seq.take 1;; // this works and returns -1
nums |> Seq.take 2;; // this overflows
同样,当我读到这个时,零应该是序列可以迭代的有效值。
复杂化我的困惑:
let nums = Seq.initInfinite id |> Seq.filter ((>=) 0);;
nums |> Seq.take 1;; // works, [0]
也许我可以通过假设过滤器实际意味着调和行为,“值无效,除非它们是> = 0”。但这不值得:
let nums = Seq.initInfinite (fun i -> i - 1) |> Seq.filter ((>=) 0);;
nums |> Seq.take 1;; // works [-1]
nums |> Seq.take 2;; // works [-1, 0]
过滤器不能定义 有效 值...对于filter ((>=) 0)
,-1不是> = 0。
过滤器不能定义 无效 值...对于0不是>在filter ((>) 0)
的情况下为0。
请为我解读这个。
答案 0 :(得分:9)
由于你如何使用谓词,它实际上意味着什么令人困惑。让我们首先解决这个问题,方法是通过过滤器推送具有已知值集的有限序列。
> let input = [-5; 0; 5 ];;
val input : int list = [-5; 0; 5]
> let output = input |> Seq.filter ((>) 0) |> Seq.toList;;
val output : int list = [-5]
等等,为什么-5
会被退回?这是因为(>) 0
实际上不是x > 0
,而是(>) 0 x
,相当于0 > x
。因此,Seq.filter ((>) 0)
与Seq.filter (fun i -> 0 > i)
相同:
> let output = input |> Seq.filter (fun i -> 0 > i) |> Seq.toList;;
val output : int list = [-5]
现在我们已经弄明白了,让我们试着查看溢出。
let nums = Seq.initInfinite id |> Seq.filter ((>) 0);;
Seq.initInfinite id
返回以0
开头的无限集合,其下一个元素等于prev + 1
。
> Seq.initInfinite id |> Seq.take 5 |> Seq.toList;;
val it : int list = [0; 1; 2; 3; 4] // this will keep going if you remove Seq.take
现在您正在添加过滤器,它只返回小于0
的元素。这有多少元素?的无!即可。因此,您的过滤器将继续询问Seq.initInfinite
中的下一个元素,直到您溢出Integer
范围并抛出异常。
答案 1 :(得分:0)
序列被懒惰地评估,所以乍一看这种行为似乎有点奇怪,因为你没有调用toList,toArray等。
实际上它只是溢出,因为你正在使用F#interactive,当你按下返回时会尝试打印序列的前几个元素。因此,它会尝试遍历您的无限序列,直到找到一些与您的谓词匹配的项目,并且永远不会找到任何项目,因此溢出。