Seq.filter和无限似乎违反直觉

coc*_*lla 2 f#

我试图理解在无限列表上应用过滤器的结果.我需要一个解释来了解幕后发生的事情.

let nums = Seq.initInfinite id |> Seq.filter ((>) 0);;
nums |> Seq.take 0;; // of course, this works
nums |> Seq.take 1;; // this overflows
Run Code Online (Sandbox Code Playgroud)

在我的阅读中,第一行意味着"在零处开始无限序列并过滤掉所有大于零的值(例如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
Run Code Online (Sandbox Code Playgroud)

同样,正如我读到的那样,零应该是序列可以迭代的有效值.

复杂化我的困惑:

let nums = Seq.initInfinite id |> Seq.filter ((>=) 0);;
nums |> Seq.take 1;; // works, [0]
Run Code Online (Sandbox Code Playgroud)

也许我可以通过假设过滤器实际上意味着"和无效的值> = 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]
Run Code Online (Sandbox Code Playgroud)

过滤器不能定义有效值 ...对于-1,在这种情况下,不是> = 0 filter ((>=) 0).

不能过滤器定义无效值的情况......对于0,在0的情况下不是> 0 filter ((>) 0).

请为我解读这个.

Mar*_*zek 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]
Run Code Online (Sandbox Code Playgroud)

等等,为什么-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]
Run Code Online (Sandbox Code Playgroud)

现在我们已经想到了,让我们试着查看溢出.

let nums = Seq.initInfinite id |> Seq.filter ((>) 0);;
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

现在你要添加过滤器,它只返回小于的元素0.这有多少元素?没有!.因此,您的过滤器将继续询问下一个元素,Seq.initInfinite直到溢出Integer范围并抛出异常.