F# 错误的FS0064警告?此构造导致代码不像类型注释所指示的那样通用
我正在尝试创建一个类,该类实现了一个通用的.NET IComparer接口,用于各种System.Collections.generic Collections。此IComparer将使用外部提供的函数将集合的值映射到排序键 示例应用程序可能是按填充进行排序的F# 错误的FS0064警告?此构造导致代码不像类型注释所指示的那样通用,f#,F#,我正在尝试创建一个类,该类实现了一个通用的.NET IComparer接口,用于各种System.Collections.generic Collections。此IComparer将使用外部提供的函数将集合的值映射到排序键 示例应用程序可能是按填充进行排序的SortedSet,但填充是从单独维护和更新的外部数据源动态检索的 open System open System.Collections.Generic type ExternalComparer<'T>(compareBy
SortedSet
,但填充是从单独维护和更新的外部数据源动态检索的
open System
open System.Collections.Generic
type ExternalComparer<'T>(compareBy: ('T -> 'U) when 'U :> IComparable) =
let compareBy = compareBy
interface IComparer<'T> with
member this.Compare(a, b) =
let x = compareBy a
let y = compareBy b
if x < y then -1 else if x > y then 1 else 0
事实上,我打算将类型变量“U”约束为“IComparable”类型,并且我试图在函数类型定义中用compareBy
时的when“U:>IComparable
约束来表达这一意图
这个警告消息是错误的,还是我做错了什么?问题是您正在定义
compareBy
类型以返回一个'U
,约束为IComparable
,而您可以更清楚地定义它以直接返回一个IComparable
,如下所示:
type ExternalComparer<'T>(compareBy: ('T -> IComparable)) =
类型外部比较器(可比较))=
由于您知道
'U
始终是一个i可比较的
,因此泛型类型的使用是不正确的。问题在于,您正在通过类型定义比较,以返回一个'U
,并将其约束为i可比较的
,当您可以更清楚地定义它以直接返回一个IComparable
时,如下所示:
type ExternalComparer<'T>(compareBy: ('T -> IComparable)) =
类型外部比较器(可比较))=
因为你知道,U
永远是一个I可比较的
,所以泛型类型的使用是不正确的。我认为你的解决方案-只要接受类型为'T->I可比较的
的函数就是正确的选择,即使这意味着ExternalComparer
的用户可能需要插入一个向上转换来编译代码
为了解释出现错误的原因,您的类只有一个泛型类型参数'T
,而'U
参数在那里缺失-因此编译器将其约束为IComparable
。如果要解决此问题,必须添加另一个通用参数:
type ExternalComparer<'T, 'U when 'U :> IComparable>(compareBy: ('T -> 'U)) =
let compareBy = compareBy
interface IComparer<'T> with
member this.Compare(a, b) =
let x = compareBy a :> IComparable
let y = compareBy b :> IComparable
if x < y then -1 else if x > y then 1 else 0
现在您可以很好地使用Create
方法:
ExternalComparer<string>(fun v -> int v :> _) // Requires upcast
ExternalComparer<string>.Create(fun v -> int v) // Works directly!
ExternalComparer(fun v->int v:>\ux)//需要上溯
Create(fun v->int v)//直接工作!
我认为您的解决方案-只接受类型为'T->IComparable
的函数是正确的,即使这意味着外部比较器的用户可能需要插入一个向上转换来编译代码
为了解释出现错误的原因,您的类只有一个泛型类型参数'T
,而'U
参数在那里缺失-因此编译器将其约束为IComparable
。如果要解决此问题,必须添加另一个通用参数:
type ExternalComparer<'T, 'U when 'U :> IComparable>(compareBy: ('T -> 'U)) =
let compareBy = compareBy
interface IComparer<'T> with
member this.Compare(a, b) =
let x = compareBy a :> IComparable
let y = compareBy b :> IComparable
if x < y then -1 else if x > y then 1 else 0
现在您可以很好地使用Create
方法:
ExternalComparer<string>(fun v -> int v :> _) // Requires upcast
ExternalComparer<string>.Create(fun v -> int v) // Works directly!
ExternalComparer(fun v->int v:>\ux)//需要上溯
Create(fun v->int v)//直接工作!
在我看来,您可以将一段代码折叠成一个对象表达式:
let bigCity = {Name="NYC"; population = 1_000_000}
let smallCity = {Name="KC"; population = 1000}
let cityComparer compFunc = { new System.Collections.Generic.IComparer<'T> with
override __.Compare(c1, c2) =
let x = compFunc c1
let y = compFunc c2
if x < y then -1 else if x > y then 1 else 0
}
let comp = cityComparer (fun x -> x.population)
comp.Compare(smallCity,bigCity)
//val it : int = -1
let bigCity={Name=“NYC”;population=1_000_000}
设smallCity={Name=“KC”;population=1000}
让cityComparer compFunc={new System.Collections.Generic.IComparer在我看来,您可以将一段代码折叠成一个对象表达式:
let bigCity = {Name="NYC"; population = 1_000_000}
let smallCity = {Name="KC"; population = 1000}
let cityComparer compFunc = { new System.Collections.Generic.IComparer<'T> with
override __.Compare(c1, c2) =
let x = compFunc c1
let y = compFunc c2
if x < y then -1 else if x > y then 1 else 0
}
let comp = cityComparer (fun x -> x.population)
comp.Compare(smallCity,bigCity)
//val it : int = -1
let bigCity={Name=“NYC”;population=1_000_000}
设smallCity={Name=“KC”;population=1000}
让cityComparer compFunc={new System.Collections.Generic.IComparer