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

时间:2013-12-18 17:42:47

标签: f#

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

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

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

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

但是当我尝试通过传递seq&lt;'K *'V&gt;来调用它时编译器在调用站点抱怨:

...类型seq与seq&gt;类型不兼容...

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

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

1 个答案:

答案 0 :(得分:8)

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

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

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

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

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

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

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

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

编辑以下示例显示第一个函数的行为符合要求:

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

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