4
votes

I'm curious how the F# Seq computational expression implements the IEnumerable data structure.

Searching Sharp.Core/seq.fs on GitHub for the implementation of yield! ( YieldFrom(expr) ) isn't successful.

2
I revised the title. The seq operator is used for casting to seq<'T> (see source). - Daniel

2 Answers

6
votes

As the specification quoted by Daniel says, sequence expressions are not treated as ordinary computation expressions - rather than translating them to builder method calls (such as seq.For, seq.Yield etc.), the compiler actually generates code that is specific for sequences. This is mainly for performance reasons - the calls to computation builder would add too much overhead.

Here are two relevant pointers:

  • The GeneratedSequenceBase type is the base class that is used by the compiler when compiling sequence expressions - there is also other library code around it that is used by the generated compiled code. See the F# library source code here.

  • The TcSequenceExpression method in the type checker is where the type checking happens. You can see that the compiler is following a different path than for ordinary computation expressions. This is here in the compiler source code.

  • The other relevant parts are in ilxgen.fs where the compiler actually generates the code after type checking - you can find the places by looking for GeneratedSequenceBase in the source code (but I'm not an expert on this part)

3
votes

See ยง6.3.11 of the spec. It states:

Logically speaking, sequence expressions can be thought of as computation expressions with a builder of type Microsoft.FSharp.Collections.SeqBuilder....However, this builder type is not actually defined in the F# library.

It goes on to show exactly how sequence expressions are elaborated by the compiler.