F# structural tuples versus BCL Tuple types

base-class-library, f#

Solution

as usual F# spec to the rescue:

6.3.2 Tuple Expressions

An expression of the form expr1, ..., exprn is a tuple expression. For example:

let three = (1,2,"3")
let blastoff = (10,9,8,7,6,5,4,3,2,1,0)

The expression has the type (ty1 * ... * tyn) for fresh types ty1 … tyn, and each individual expression ei is checked using initial type tyi.

Tuple types and expressions are translated into applications of a family of F# library types named System.Tuple. Tuple types ty1 * ... * tyn are translated as follows:

- For n <= 7 the elaborated form is `Tuple<ty1,...,tyn>`.

- For larger n, tuple types are shorthand for applications of the additional F# library type `System.Tuple<_>` as follows:

- For n = 8 the elaborated form is `Tuple<ty1,...,ty7,Tuple<ty8>>`.

- For 9 <= n the elaborated form is `Tuple<ty1,...,ty7,tyB>` where tyB is the converted form of the type (ty8 ... tyn).

Tuple expressions (expr1,...,exprn) are translated as follows:

- For n <= 7 the elaborated form `new Tuple<ty1,…,tyn>(expr1,...,exprn)`.

- For n = 8 the elaborated form `new Tuple<ty1,…,ty7,Tuple<ty8>>(expr1,...,expr7, new Tuple<ty8>(expr8)`.

- For 9 <= n the elaborated form `new Tuple<ty1,...ty7,ty8n>(expr1,..., expr7, new ty8n(e8n)` where ty8n is the type (ty8*...* tyn) and expr8n is the elaborated form of the expression expr8,..., exprn.

When considered as static types, tuple types are distinct from their encoded form. However, the encoded form of tuple values and types is visible in the F# type system through runtime types. For example, typeof is equivalent to `typeof<System.Tuple<int,int>>` , and (1,2) has the runtime type `System.Tuple<int,int>`. Likewise, (1,2,3,4,5,6,7,8,9) has the runtime type `Tuple<int,int,int,int,int,int,int,Tuple<int,int>>`.

NOTE: prior to adding tuples to BCL in .NET 4.0 F# used System.Tuple type defined in FSharp.Core dll

I guess the only way for you to deal with tuples having arbitrary size is to resort to constructing and deconstructing then with functions from `Microsoft.FSharp.Reflection.FSharpType\FSharpValue`

Problem

In F# you can define a `first` function as follows: `let first (x, y) = x` You can call it like this: `first (1, 2)` You can also define the same function in terms of the BCL `Tuple` type: `let first (t:Tuple<_, _ >) = t.Item1` However, you cannot call it using the prior syntax, or you will get the following error: `error FS0001: The type ''c * 'd' is not compatible with the type 'Tuple<'a,'b>'` Instead, you have to do the following: `first (Tuple<_,_>(1, 2))` This is strange, since compiled F# code does seem to use `Tuple` to represent its parameters in either case. So why is the F# compiler telling me that the types are not compatible? Why does any of this matter? Well, basically I want to write a method with overloads supporting a tuple of arbitrary length. This is impossible with F#'s syntactic tuples, since the exact number of arguments must be known in advance. However, it does seem possible by using the BCL `Tuple` types, because those use the `TRest` trick to allow tuples of arbitrary length. Unfortunately, if I write my overloads this way, then they won't work with F# syntactic tuples, which is the ultimate goal. So my question is: why aren't syntactic tuples and BCL tuples compatible? And also, are there any examples of writing functions and/or methods that operate on arbitrary-length tuples in F#? The specific application deals with a type inference-based binary parsing library I'm writing. You can view the code here. You can see the many overloads that I have for tuples, but I don't want to extend them out to some magic number.

Original source