#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
ключевым словом.) Если бы автор просто сделал копию, эти переменные не были бы изменяемыми.