为什么在这种情况下使用引用,在 F# 中

Why use references in this scenario, in F#

我在网上找到这段代码:

let tripleWise (source: seq<_>) =
    seq {
            use e = source.GetEnumerator()
            if e.MoveNext() then
                let i = ref e.Current
                if e.MoveNext() then
                    let j = ref e.Current
                    while e.MoveNext() do
                        let k = e.Current
                        yield (!i, !j, k)
                        i := !j
                        j := k
        }

它类似于成对的,但会生成三胞胎。

我很好奇作者为什么引用这些行:

let i = ref e.Current
let j = ref e.Current

而不是复制值,而他直接在循环中复制值。

作者使用 Seq.pairwise 的实现作为他的出发点。 pairwise 的当前代码如下所示:

let pairwise (source: seq<'T>) =
    checkNonNull "source" source
    seq { use ie = source.GetEnumerator()
          if ie.MoveNext() then
              let mutable iref = ie.Current
              while ie.MoveNext() do
                  let j = ie.Current
                  yield (iref, j)
                  iref <- j }

可变变量的名字很奇怪 iref。果然,在早期版本中它是一个 ref cell。在此提交中,其中很多被替换为可变变量:

https://github.com/dotnet/fsharp/pull/8063

这样做主要是为了便于阅读。

很明显,作者的代码是基于 Seq.pairwise 的早期版本。

我认为您问题的直接答案是 ij 需要可变,而 k 不需要。 (当引用单元格是 F# 中改变数据的标准方法而不是 mutable 关键字时,原始代码可能被写回了。)如果作者只是复制一份,这些变量将不会可变。