定义一个接受一系列元组的F#Generic函数

3Sp*_*ere 2 f#

我试图在F#3.0中编写一个函数,它接受一系列元组并返回一个字典,但我似乎无法使语法正确.目标是传递一系列类型为'K*'V的元组并创建一个Dictionary <'K,'V>.虽然我尝试了各种排列,但我无法让编译器接受我的语法,例如:

CreateDictionary<'K, 'V, 'T when 'K : equality and T : 'K*'V>(s : seq<'T>)
Run Code Online (Sandbox Code Playgroud)

另一方面,该声明被接受:

CreateDictionary<'K, 'V when 'K : equality>(s : seq< Tuple<'K,'V> >)
Run Code Online (Sandbox Code Playgroud)

但是当我尝试通过传递seq <'K*'V>来调用它时,编译器在调用站点上抱怨:

...类型seq与seq类型不兼容> ...

这令人困惑,因为我认为F#元组对应于System.Tuple <>.所以,显然我在这里遗漏了一些东西.

声明接受一系列元组的泛型方法的最佳方法是什么?

Tom*_*cek 8

您不需要为元组类型定义新的泛型类型:

let CreateDictionary<'K, 'V when 'K : equality>(s : seq<'K*'V>) = 
  (...)
Run Code Online (Sandbox Code Playgroud)

这很好,因为你只想说参数是一系列键值对,其中键支持相等.您尝试编写的那种约束在某些情况下可能很有用,但不是在这里 - 请尝试以下操作:

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

这就是说你想要一个类型值的序列,'T其中'T某些类型继承自'K * 'V(aka Tuple<'K, 'V>).但由于元组类型是密封的,编译器会给出一个错误,说明这个约束没有用.

但它在某些情况下可能很有用 - 你可以编写一个函数,它接受实现序列接口的任何类型:

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

通常不需要这样做,因为当它们用作函数参数时,F#会自动将列表,数组等转换为序列,但如果你有一个包含任何集合作为第二个参数的元组,它会很有用.

编辑这是一个示例,显示第一个函数按要求运行:

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

CreateDictionary [1,"hi"]    // Compiles fine
CreateDictionary [A(),"hi"]  // Error
Run Code Online (Sandbox Code Playgroud)