On 2 February 2015 at 14:11, Greg Keogh <[email protected]> wrote:

> What's the neatest way of generating an F# sequence of integers of the
> form 6n±1, so I get this:
>
> 5, 7, 11, 13, 17, 19, 23, 25, ...
>

Although I am not an F# expert, I looked at this because I am interested in
how expressive F# really is when compared to C# and compared to other
functional languages. My answers are below, but I would love to see some
better ones from real F# gurus.

I am assuming arbitrarily high "n", beyond "long.MaxValue". Otherwise the
answer is likely to be an engineer's hack that probably misses the point of
your question.

Like I said, I am not an F# expert by any means. I have yet to find a
succinct F# expression for the (infinite) sequence of positive integers.
The best I have been able to find so far uses "unfold":

Seq.unfold (fun n -> Some (n, n + 1I)) 1I


...which I find unacceptable because it hides the true nature of the
integer sequence behind an explicit state transition, not to mention a lot
of keystrokes and punctuation.

Anyway, you could build on this (or a shorter expression that yields the
same sequence) with an imperative-style "sequence expression", similar to a
C# version that uses "yield return":

seq {

    for n in Seq.unfold (fun n -> Some (n, n + 1I)) 1I do

        yield 6I * n - 1I

        yield 6I * n + 1I

}


Compare this to the C# version (which luckily converts int literals to
BigInteger automatically):

for (var n = BigInteger.One; ; n = n + 1)
{
    yield return 6 * n - 1;
    yield return 6 * n + 1;
}


While neither is the one-liner you are probably after, I personally think
the C# version is actually more succinct in this instance, due to the
unwieldy use of "unfold" in the F# version for what should be trivial in a
functional language that has lazy sequences. Of course, the C# version is
technically not an expression at all.

You could also build the sequence directly into the unfold generator, but
that results in a list of lists, which would need to be flattened:

1I |> Seq.unfold (fun n -> Some ([6I * n - 1I; 6I * n + 1I], n + 1I)) |>
Seq.concat


Although this is a one-liner and more in the spirit of F#, I personally do
not find this to be a very good solution either. The "unfold" still hides
the nature of the generating integer sequence. The "concat" is only there
to tweak the in-memory representation of the sequence and has no meaning
relevant to the sequence.

There is a similar solution that uses "collect" instead of "concat":

1I |> Seq.unfold (fun n -> Some (n, n + 1I)) |> Seq.collect (fun n -> [6I *
n - 1I; 6I * n + 1I])


I find this version marginally better, perhaps only for the reason that the
"collect" call has an actual purpose beyond tweaking the representation.

[OT] If you're interested, compare these to the Haskell solution which uses
a list comprehension (cf. mathematical set builder notation).

[6 * n + m | n <- [1..], m <- [-1, 1]]


--
Thomas Koster

Reply via email to