Generics 将成员约束添加到内联函数的参数会导致数组访问器上出现FS0752

Generics 将成员约束添加到内联函数的参数会导致数组访问器上出现FS0752,generics,f#,type-constraints,arrayaccess,Generics,F#,Type Constraints,Arrayaccess,我已经一遍又一遍地阅读了,但是我不明白为什么这段代码不能编译: let inline transform<'A, 'a when 'A : (member Item : int -> float)> (a: 'A) : 'a = a.[0] 正如您所看到的,这些函数执行完全相同的操作,但操作的类型不同 我想得到一个通用函数,比如不工作代码: let inline transform<'A, 'a when 'A : (member Item : int ->

我已经一遍又一遍地阅读了,但是我不明白为什么这段代码不能编译:

let inline transform<'A, 'a when 'A : (member Item : int -> float)> (a: 'A) : 'a =
    a.[0]
正如您所看到的,这些函数执行完全相同的操作,但操作的类型不同

我想得到一个通用函数,比如不工作代码:

let inline transform<'A, 'a when 'A : (member Item : int -> 'a)> (toExt : 'a list -> 'A) (a: 'A) : 'A =
    let x1, y1 = l1 * cos a.[0], l1 * sin a.[0]
    let x2, y2 = x1 + l2 * cos (a.[0] + a.[1]), y1 + l2 * sin (a.[0] + a.[1])
    toExt [x1; y1; x2; y2]

let transformVec = transform vector
let transformDV = transform toDV  
因为它强制“警告FS0064是浮动的,我不想。。。来自DiffSharp的DV返回get_项上的D类型,而不是浮点

将声明替换为

let inline transform<'a> (toExt : 'a list -> 'A) (a: 'A) : 'A = 
使编译器发出咯咯声:

错误FS0001:此处无法使用声明的类型参数“a”,因为无法在编译时解析该类型参数


您需要这样调用成员项:

let inline transform (a: 'A) : 'a = (^A : (member get_Item: _ -> _) a, 0)
但是你会得到一个警告

~vs72B.fsx(2,5): warning FS0077: Member constraints with the name 'get_Item' are given special status by the F# compiler as certain .NET types are implicitly augmented with this member. This may result in runtime failures if you attempt to invoke the member constraint from your own code.
因为某些基本类型使用模拟成员。因此,对于列表,它将起作用:

transform ["element"]
// val it : string = "element"
但不适用于阵列

transform [|"element"|]
System.NotSupportedException: Specified method is not supported.
at <StartupCode$FSI_0009>.$FSI_0009.main@()
Stopped due to error
我不确定它是否能与DiffSharp一起使用,我不知道您使用的是该库中的哪种类型,我多次找到DV

更新2

关于泛型转换函数的后续问题,仅使用简单的成员约束是不够的,您还需要解决从列表到目标类型的转换问题,并创建一个不同的泛型乘法,该乘法可以泛型工作,但与您选择的类型一起工作 需要处理。可以将重载与成员约束结合使用,以获得所需的功能:

let inline item (i:int) (a: 'A) : 'a = (^A : (member get_Item: _ -> _) a, i)

type T = T with
    static member ($) (T, _:Vector<float>) = fun (x:float list) -> vector x
    static member ($) (T, _:Matrix<float>) = fun (x:float list) -> matrix [x]
    static member ($) (T, _:DV           ) = fun (x: D list  ) -> toDV (List.toArray x)

let inline toDestType (x:'t list) :'D = (T $ Unchecked.defaultof<'D>) x

type V = V with
    static member ($) (V, x:float        ) = fun (y: float) -> x * y : float
    static member ($) (V, x:D            ) = fun (y: float) -> x * y : D

let inline mult (y:float) (x:'t)  :'t = (V $ x) y

let inline transform (a:'T) :'T =
    let x1, y1 = mult l1 (cos (item 0 a)), mult l1 (sin (item 0 a))
    let x2, y2 = x1 + mult l2 (cos ((item 0 a) + (item 1 a))), y1 + mult l2 (sin ((item 0 a) + (item 1 a)))
    let g = toDestType [x1; y1; x2; y2]
    g 

let b = transform  (DV [| 1. ;  2.|])
let a = transform  (vector [1. ; 2.])

每次引用DiffSharp时,我仍然会收到一个运行时错误,但是intellisense显示了正确的推断类型。

您需要像这样调用成员项:

let inline transform (a: 'A) : 'a = (^A : (member get_Item: _ -> _) a, 0)
但是你会得到一个警告

~vs72B.fsx(2,5): warning FS0077: Member constraints with the name 'get_Item' are given special status by the F# compiler as certain .NET types are implicitly augmented with this member. This may result in runtime failures if you attempt to invoke the member constraint from your own code.
因为某些基本类型使用模拟成员。因此,对于列表,它将起作用:

transform ["element"]
// val it : string = "element"
但不适用于阵列

transform [|"element"|]
System.NotSupportedException: Specified method is not supported.
at <StartupCode$FSI_0009>.$FSI_0009.main@()
Stopped due to error
我不确定它是否能与DiffSharp一起使用,我不知道您使用的是该库中的哪种类型,我多次找到DV

更新2

关于泛型转换函数的后续问题,仅使用简单的成员约束是不够的,您还需要解决从列表到目标类型的转换问题,并创建一个不同的泛型乘法,该乘法可以泛型工作,但与您选择的类型一起工作 需要处理。可以将重载与成员约束结合使用,以获得所需的功能:

let inline item (i:int) (a: 'A) : 'a = (^A : (member get_Item: _ -> _) a, i)

type T = T with
    static member ($) (T, _:Vector<float>) = fun (x:float list) -> vector x
    static member ($) (T, _:Matrix<float>) = fun (x:float list) -> matrix [x]
    static member ($) (T, _:DV           ) = fun (x: D list  ) -> toDV (List.toArray x)

let inline toDestType (x:'t list) :'D = (T $ Unchecked.defaultof<'D>) x

type V = V with
    static member ($) (V, x:float        ) = fun (y: float) -> x * y : float
    static member ($) (V, x:D            ) = fun (y: float) -> x * y : D

let inline mult (y:float) (x:'t)  :'t = (V $ x) y

let inline transform (a:'T) :'T =
    let x1, y1 = mult l1 (cos (item 0 a)), mult l1 (sin (item 0 a))
    let x2, y2 = x1 + mult l2 (cos ((item 0 a) + (item 1 a))), y1 + mult l2 (sin ((item 0 a) + (item 1 a)))
    let g = toDestType [x1; y1; x2; y2]
    g 

let b = transform  (DV [| 1. ;  2.|])
let a = transform  (vector [1. ; 2.])

每次引用DiffSharp时,我仍然会收到一个运行时错误,但是intellisense显示了正确的推断类型。

我在Mathnet中使用了它。Numerics的Vector但不适用于DiffSharp的DV,它的get_项返回D类型,而不是float。但是当使用。[]运算符时,它在DiffSharp的DV中返回什么?D类型值OK,所以,如果它在正常调用时返回一个D,为什么在使用静态约束调用时它会返回不同的结果呢?它不会,只是我不能生成一个通用的转换函数来解释“a”的非浮点值。请参见上面的编辑。我让它用于Mathnet.Numerics的向量,但不用于DiffSharp的DV,谁的get_项返回D type,而不是float。但是当您使用。[]运算符时,它在DiffSharp的DV中返回什么?D type value确定,那么如果它在正常调用时返回D,为什么在使用静态约束调用时它会返回不同的值?它不会,只是我不能生成一个通用的转换函数来解释“a”的非浮点值,请参见上面的编辑。