首页 文章

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

提问于
浏览
2

我试图在F#3.0中编写一个函数,它接受一系列元组并返回一个字典,但我似乎无法使语法正确 . 目标是传递一系列类型为'K *'V的元组并创建一个Dictionary <'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 <'K *'V>来调用它时,编译器在调用站点上抱怨:

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

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

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

1 回答

  • 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#会在将列表,数组等用作函数参数时自动将它们转换为序列,但是如果你有这样的话,那么它很有用 . 包含任何集合作为第二个参数的元组 .

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

    [<NoEqualityAttribute;NoComparisonAttribute>]
    type A() = class end
    
    CreateDictionary [1,"hi"]    // Compiles fine
    CreateDictionary [A(),"hi"]  // Error
    

相关问题