3Sphere
3Sphere

Reputation: 249

Defining an F# Generic function that accepts a sequence of tuples

I am trying to write a function in F# 3.0 that accepts a sequence of tuples and returns a Dictionary but I can't seem to get the syntax right. The goal is to pass in a sequence of tuples of type 'K*'V and create a Dictionary<'K,'V>. Although I have tried various permutations, I cannot get the compiler to accept my syntax, for example:

CreateDictionary<'K, 'V, 'T when 'K : equality and T : 'K*'V>(s : seq<'T>)

On the other hand, this declaration is accepted:

CreateDictionary<'K, 'V when 'K : equality>(s : seq< Tuple<'K,'V> >)

but when I try to call it by passing seq<'K*'V> the compiler complains at the call site that:

...the type seq is not compatible with the type seq>...

Which is confusing because I thought that F# tuples corresponded to System.Tuple<>. So, obviously I'm missing something here.

What is the best way to declare a generic method that accepts a sequence of tuples?

Upvotes: 3

Views: 1340

Answers (1)

Tomas Petricek
Tomas Petricek

Reputation: 243126

You do not need to define a new generic type for the tuple type:

let CreateDictionary<'K, 'V when 'K : equality>(s : seq<'K*'V>) = 
  (...)

This is fine, because you just want to say that the argument is a sequence of key value pairs where the key supports equality. The sort of constraint that you were trying to write might be useful in some cases, but not here - try the following:

let CreateDictionary<'K, 'V, 'T when 'K : equality and 'T :> 'K*'V>(s : seq<'T>) = 
  (...)

This would be saying that you want a sequence of values of type 'T where 'T is some type that inherits from 'K * 'V (aka Tuple<'K, 'V>). But since the tuple type is sealed, the compiler will give you an error saying that this constraint is not useful.

But it could be useful in some cases - you could write a function that takes any type that implements the sequence interface:

let CreateDictionary<'K, 'V, 'T when 'K : equality and 'T :> seq<'K*'V>>(s : 'T) = 
  (...)

This is not usually needed because F# will automatically convert lists, arrays, etc. to sequence when they are used as function arguments, but it is useful if you had e.g. a tuple containing any collection as a second argument.

EDIT And here is an example showing that the first function behaves as required:

[<NoEqualityAttribute;NoComparisonAttribute>]
type A() = class end

CreateDictionary [1,"hi"]    // Compiles fine
CreateDictionary [A(),"hi"]  // Error

Upvotes: 9

Related Questions