Question

So I have the following code which is giving a type mismatch compiler error, and I don't know why:

[<Test>]
member this.TheTest() =
    let tuple = (DateTime.Now, 10)
    let listOfTuples = [ tuple ]
    SomeType.SomeFunc(listOfTuples)

static member SomeFunc (listOfTuples: IEnumerable<Tuple<DateTime,int>>) =
    Console.WriteLine("foo")

Why are the types not compatible?

And more importantly, how can I express SomeFunc's signature to be compatible with the call?

Was it helpful?

Solution

The actual issue here is trying to pass ('a * 'b) into a function taking Tuple<'a, 'b>. While the internal representation of these are the same, the F# compiler treats the two differently.

This is spelled out in the F# language spec, section 6.3.2:

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.

The issue is that the compiler is using the "static types" to see if this function is a match, and according to the spec, it isn't.

And more importantly, how can I express SomeFunc's signature to be compatible with the call?

You can work around this in various ways. The simplest is to redefine the type specifications on your method to use tuple expressions as well:

static member SomeFunc (listOfTuples: IEnumerable<(DateTime * int)>) =
    Console.WriteLine("foo")

Note that the above can be written in a more idiomatic manner (with the exact same meaning) as:

static member SomeFunc (listOfTuples: (DateTime * int) seq) =
    Console.WriteLine("foo")
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top