为什么类型推断不能自动确定属性上存在的属性?

ale*_*hro 1 f# type-inference

我需要比较不同类型的对象,我知道它们都有属性Id和Legacy_id.不幸的是我无法为它们添加接口,因为类型来自数据库模式.我希望以下比较器可以工作:

type Comparer<'T >()=
  interface System.Collections.Generic.IEqualityComparer<'T> with 
    member this.Equals (o1:'T,o2:'T)=
      o1.Legacy_id=o2.Legacy_id
    member this.GetHashCode(o:'T)=
      o.Id+o.Legacy_id
Run Code Online (Sandbox Code Playgroud)

此外,我还有类型的比较器类型的实例化.所以,理论上编译器有足够的信息.

但是它给出了一个错误:"基于此程序点之前的信息查找不确定类型的对象.在此程序点之前可能需要类型注释来约束对象的类型.这可以允许解析查找. "

我想知道为什么F#在这里失败了?是否有任何实际/理论限制或者它没有实施?这种推断可能非常有用.

我怀疑解释是关于F#编译器只是向前走.C#的限制没有.这是错误消息抱怨的内容.是这样吗?

The*_*ght 6

成员约束不能用于类型,这就是你不能这样做的原因.看到这里.

你可以做的是创建一个比较器类,它接受特定类型的显式相等检查和哈希码生成函数,例如

type Comparer<'T>(equalityFunc, hashFunc) =
  interface System.Collections.Generic.IEqualityComparer<'T> with 
    member this.Equals (o1:'T,o2:'T)=
      equalityFunc o1 o2
    member this.GetHashCode(o:'T)=
      hashFunc o
Run Code Online (Sandbox Code Playgroud)

然后,您可以使用内联函数为与您要强加的约束匹配的类型生成上述实例:

let inline id obj =
    ( ^T : (member Id : int) (obj))

let inline legacyId obj =
    ( ^T : (member Legacy_id : int) (obj))

let inline equals o1 o2 =
    id o1 = id o2

let inline hash o =
    id o + legacyId o

let inline createComparer< ^T when ^T : (member Id: int) and ^T : (member Legacy_id : int) >() =
    Comparer< ^T >(equals, hash) :> System.Collections.Generic.IEqualityComparer< ^T >
Run Code Online (Sandbox Code Playgroud)

假设您有一些TestType具有两个必需属性的类型:

type TestType =
   member this.Legacy_id = 7
   member this.Id = 9
Run Code Online (Sandbox Code Playgroud)

例如,您可以createComparer<TestType>()生成适合您的类型的相等比较器.

  • @alehro F#的静态解析类型参数仍然比C++模板灵活性差.例如,没有办法像使用例如`template <int N>那样参数化值,但它们确实允许模拟更高的kinded多态. (3认同)

Car*_*Dev 5

获取比较器的简洁方法,例如创建一个HashSet是:

let inline getId o = (^T : (member Id : int) o)
let inline getLegacyId o = (^T : (member Legacy_id : int) o)

let inline legacyComparer< ^T when ^T : (member Id : int) and ^T : (member Legacy_id : int)>() =
    { new System.Collections.Generic.IEqualityComparer<'T> with
          member __.GetHashCode o = getId o + getLegacyId o
          member __.Equals(o1, o2) = getLegacyId o1 = getLegacyId o2 }
Run Code Online (Sandbox Code Playgroud)

类型推断是关于推断一个类型,而不是证明了一些通用的类型参数满足任意条件的所有实例(见名义与结构类型系统).SO上的静态解析类型参数有很多好的答案.