Thomas
Thomas

Reputation: 12137

Why use references in this scenario, in F#

I found this code online:

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
        }

it's similar to pairwise, but makes triplets.

I am curious as to why the author takes a reference on these lines:

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

instead of copying the value, while he copies the value directly in the loop.

Upvotes: 1

Views: 79

Answers (2)

Brian Berns
Brian Berns

Reputation: 17153

I think the direct answer to your question is that i and j need to be mutable, whereas k does not. (The original code was probably written back when reference cells were the standard way to mutate data in F#, rather than the mutable keyword.) Had the author simply taken a copy, those variables wouldn't be mutable.

Upvotes: 1

Jim Foye
Jim Foye

Reputation: 2036

The author used as his starting point the implementation of Seq.pairwise. The current code for pairwise looks like this:

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 }

The mutable variable is rather strangely named iref. Sure enough, in an earlier version it was a ref cell. Lots of these were replaced with mutable variables in this commit:

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

This was mainly done for readability.

Clearly the author had based his code on the earlier version of Seq.pairwise.

Upvotes: 2

Related Questions