我一遍又一遍地阅读有关类型约束的官方 Microsoft 文档,但我不明白为什么这段代码无法编译:
let inline transform<'A, 'a when 'A : (member Item : int -> float)> (a: 'A) : 'a =
a.[0]
错误 FS0752:运算符 'expr.[idx]' 已根据此程序点之前的信息用于不确定类型的对象。考虑添加更多类型约束
与 :
let inline transform<'A, 'a when 'A : (member f : int -> float)> (a: 'A) : 'a =
a.f(0)
错误 FS0072:根据此程序点之前的信息查找不确定类型的对象。在这个程序点之前可能需要一个类型注释来约束对象的类型。这可以允许解析查找。
显然我不明白如何在 f# 中将成员约束与泛型一起使用。我面临的一般问题是我想通过“类矢量”类型(如 standard float[]
,甚至Vector<float>
来自DiffSharp包)创建通用函数。现在我必须为每种类型获取一个临时函数,例如(完整代码):MathNet.Numerics
DV
#I ".paket/load"
#load "mathnet.numerics.fsharp.fsx"
#load "diffsharp.fsx"
open DiffSharp.AD.Float64
open MathNet.Numerics
open MathNet.Numerics.LinearAlgebra
open MathNet.Numerics.LinearAlgebra.Double
let l1 = 4.5
let l2 = 2.5
let a0 = [1.1; -0.9]
let inline transformVec (a:Vector<float>) =
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])
vector [x1; y1; x2; y2]
let inline transformDV (a:DV) =
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])
toDV [x1; y1; x2; y2]
正如你所看到的,这个函数做的事情完全相同,但作用于不同的类型。
我想获得一个通用函数,例如(不工作的代码):
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
我错过了什么?
编辑:我已经完成了一半Mathnet.Numerics
let inline transform (toExt : 'a list -> 'A) (a: 'A) : 'A =
let inline get i : 'a = (^A : (member get_Item: int -> 'a) a,i)
let x1, y1 = l1 * cos (get(0)), l1 * sin (get(0))
let x2, y2 = x1 + l2 * cos (get(0) + get(1)), y1 + l2 * sin (get(0) + get(1))
toExt [x1; y1; x2; y2]
(transform vector) (vector a0)
因为它强制'a
(warning FS0064
) 是float
,我不希望...(DV
从DiffSharp
返回D
类型 on get_Item
,不是float
。)
将声明替换为
let inline transform<'a> (toExt : 'a list -> 'A) (a: 'A) : 'A =
使编译器发出嘶哑的声音:
错误 FS0001:此处不能使用声明的类型参数“a”,因为在编译时无法解析类型参数