使用泛型类型和静态成员的意外编译器警告

Rin*_*gil 1 generics f#

我想创建自己的列表类型CountedList<'T>,其中包含一个普通的F#列表以及列表中#元素的计数(因此我不必遍历整个列表来获取元素数).

这是我的尝试:

type CountedList<'T> = {List: 'T list; Count: int}
                        static member Empty<'a> () = {List=List.empty<'a>; Count=0}
                        member this.AddOne(element) = {this with List=element::this.List; Count=this.Count + 1}
Run Code Online (Sandbox Code Playgroud)

我们的想法是从某种类型的CountList.Empty开始,然后通过AddOne方法添加一个元素.

但是,当我尝试使用以下方法创建空列表时:

let emptyDoubleList = CountedList.Empty<double>()   
Run Code Online (Sandbox Code Playgroud)

我收到以下警告:

The instantiation of the generic type 'CountedList' is missing and can't be inferred from the arguments or return type of this member. Consider providing a type instantiation when accessing this type, e.g. 'CountedList<_>'.
Run Code Online (Sandbox Code Playgroud)

然而直接这样做:

let directEmptyDoubleList = {List=List.empty<double>; Count=0}
Run Code Online (Sandbox Code Playgroud)

没有给出警告.

为什么我会收到此警告?编译器是否应该能够意识到它是一个CountedList?此外,任何有关如何改进我的CountedList实现的建议也将受到赞赏.

这是完整的代码示例:

type CountedList<'T> = {List: 'T list; Count: int}
                            static member Empty<'a> () = {List=List.empty<'a>; Count=0}
                            member this.AddOne(element) = {this with List=element::this.List; Count=this.Count + 1}

let emptyDoubleList = CountedList.Empty<double>()   //Why does this give me a warning??

let directEmptyDoubleList = {List=List.empty<double>; Count=0}
Run Code Online (Sandbox Code Playgroud)

kvb*_*kvb 6

那是因为方法的类型参数Empty<_>不必与CountedList<_>类的类型参数匹配.因此CountedList<string>.Empty<double>(),一个有效的方法调用将返回一个CountedList<double>,并且编译器无法确定这是否是您想要的.

您可能希望创建Empty一个非泛型方法,并List.empty<'T>在其正文中使用(您可以调用它CountedList<double>.Empty(),或者只是CountedList.Empty()在编译器可以推断出类型的泛型参数的上下文中).或者,您可能希望创建一个伴随CountedList模块并empty在其中创建一个通用函数,并Empty<_>从您的类中删除该方法.