如何在F#中实现Generic.Dictionary的扩展方法(类型约束)

use*_*761 5 f#

可能重复:输入
扩展错误

我想在F#中添加一个扩展方法到System.Collections.Generic.Dictionary.麻烦的是我似乎无法正确地获得类型约束.我希望以下内容能起作用:

type Dictionary<'k, 'd when 'k : equality> with

   static member ofList (xs:list<'k * 'd>) : Dictionary<'k, 'd> =
       let res = new Dictionary<'k, 'd> ()
       for (k, d) in xs do
           res.Add (k, d)
       res
Run Code Online (Sandbox Code Playgroud)

但是,编译器抱怨我的声明与Dictionary的声明不同.当我省略等式约束时,它不会产生那个特定的错误.但随后它警告它失踪了.非常感谢任何提示,最好是其他"提高警告级别":-)

编辑

非常感谢KVB提供了我想要的答案.

type Dictionary<'k, 'd> with

static member ofList (xs:list<'k * 'd>) : Dictionary<'k, 'd> =

    let res = new Dictionary<'k, 'd> (EqualityComparer<'k>.Default)
    for (k, d) in xs do
        res.Add (k, d)
    res
Run Code Online (Sandbox Code Playgroud)

编辑:这是一个更好地解释我对RJ的回复的例子.它表明,在实例化类型时类型参数是可选的,前提是编译器可以推断它们.它编译时没有警告或错误.

type System.Collections.Generic.Dictionary<'k, 'd> with
   static member test (dict:System.Collections.Generic.Dictionary<'k, 'd>) : bool =
        dict.Values |> List.ofSeq |> List.isEmpty


let test (x:System.Collections.Generic.Dictionary<'k, 'd>) =
    System.Collections.Generic.Dictionary.test x
Run Code Online (Sandbox Code Playgroud)

Joh*_*mer 5

由于某种原因,类型参数的名称必须匹配 - 这对我来说很好

open System.Collections.Generic
type Dictionary<'TKey, 'TValue>  with
   static member ofList (xs:list<'k * 'd>) : Dictionary<'k, 'd> =
       let res = new Dictionary<'k, 'd> ()
       for (k, d) in xs do
           res.Add (k, d)
       res
Run Code Online (Sandbox Code Playgroud)

我不知道为什么会这样(30秒看看规范也没有提供任何线索).

更新 - 错误实际上是Dictionary参数与方法中写入的相同 - 执行

type Dictionary<'a, 'b>  with
   static member ofList (xs:list<'k * 'd>) : Dictionary<'k, 'd> =
       let res = new Dictionary<'k, 'd> ()
       for (k, d) in xs do
           res.Add (k, d)
       res
Run Code Online (Sandbox Code Playgroud)

工作得很好.这实际上现在是有道理的.当参数相同时,还有一个未指定的约束 - 'k:equality由于new Dictionary<'k,'d>.但是,出于某种原因,我们不能在扩展定义中放置约束(避免重复?),因此存在错误.


Dan*_*iel 3

如果您需要ofSeq各种集合的函数,您可以考虑类似于 C# 集合初始值设定项的方法。也就是说,让它适用于任何带有Add方法的集合。这也回避了你目前的问题。

open System.Collections.Generic
open System.Collections.Concurrent

module Dictionary =
  let inline ofSeq s = 
    let t = new ^T()
    for k, v in s do
      (^T : (member Add : ^K * ^V -> ^R) (t, k, v)) |> ignore
    t

module Collection =
  let inline ofSeq s = 
    let t = new ^T()
    for v in s do
      (^T : (member Add : ^V -> ^R) (t, v)) |> ignore
    t

open Dictionary

let xs = List.init 9 (fun i -> string i, i)
let d1 : Dictionary<_,_> = ofSeq xs
let d2 : SortedDictionary<_,_> = ofSeq xs
let d3 : SortedList<_,_> = ofSeq xs

open Collection

let ys = List.init 9 id
let c1 : ResizeArray<_> = ofSeq ys
let c2 : HashSet<_> = ofSeq ys
let c3 : ConcurrentBag<_> = ofSeq ys
Run Code Online (Sandbox Code Playgroud)

有趣的是,您甚至可以将其限制为具有特定构造函数重载的集合类型。例如,如果您想使用结构相等,您可以这样做:

let t = (^T : (new : IEqualityComparer< ^K > -> ^T) (HashIdentity.Structural))
Run Code Online (Sandbox Code Playgroud)