Зачем использовать ссылки в этом сценарии, в F#

#f# #reference

Вопрос:

Я нашел этот код в Интернете:

 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
 

вместо копирования значения, в то время как он копирует значение непосредственно в цикле.

Ответ №1:

Автор использовал в качестве отправной точки реализацию Seq.попарно. Текущий код для попарно выглядит следующим образом:

 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. Многие из них были заменены изменяемыми переменными в этой фиксации:

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

Это было сделано в основном для удобства чтения.

Очевидно, что автор основывал свой код на более ранней версии Seq.попарно.

Комментарии:

1. @brianberns прав, k не обязательно должен быть изменяемым; мой ответ просто дает историю, чтобы объяснить, почему код выглядит так, как он выглядит.

Ответ №2:

Я думаю, что прямой ответ на ваш вопрос заключается в том, что i и j нужно быть изменчивым, тогда k как это не так. (Исходный код, вероятно, был написан еще тогда, когда ссылочные ячейки были стандартным способом изменения данных в F#, а не mutable ключевым словом.) Если бы автор просто сделал копию, эти переменные не были бы изменяемыми.