F#类型推断和某种通用的函数参数
我的函数如下所示:F#类型推断和某种通用的函数参数,f#,F#,我的函数如下所示: let inline fmingd f' x0 alpha = let rec step x i = if i >= 100 then x else step (x - alpha*(f' x)) (i+1) step x0 0 let inline fmingd (f':^a -> ^a) (x0:^a) (alpha:float) : ^a when ^a : (static member ( * ) : float * ^a
let inline fmingd f' x0 alpha =
let rec step x i =
if i >= 100 then x
else step (x - alpha*(f' x)) (i+1)
step x0 0
let inline fmingd (f':^a -> ^a) (x0:^a) (alpha:float) : ^a
when ^a : (static member ( * ) : float * ^a -> ^a) and
^a : (static member ( - ) : ^a * ^a -> ^a) =
let rec step x i =
if i >= 100 then x
else step (x - alpha*(f' x)) (i+1)
step x0 0
它足够通用,可以使用浮动:
let f' x = 4.*x + 3.
let fminx = fmingd f' 0. 0.1
。。。和(MathNet.Numeric)向量:
这应该是可行的,因为向量有带浮点->向量->向量的操作符(*),和带向量->向量->向量的操作符(-)
但一旦我这样做了,函数就变成非泛型的。。它只接受并返回浮动。其类型签名变为:
val inline fmingd : f':(float -> float) -> x0:float -> alpha:float -> float
在将alpha限制为浮动的同时,如何保持f',x0和fmingds返回值的通用性
为了给F#编译器留下深刻印象,我提出了以下建议:
let inline fmingd f' x0 alpha =
let rec step x i =
if i >= 100 then x
else step (x - alpha*(f' x)) (i+1)
step x0 0
let inline fmingd (f':^a -> ^a) (x0:^a) (alpha:float) : ^a
when ^a : (static member ( * ) : float * ^a -> ^a) and
^a : (static member ( - ) : ^a * ^a -> ^a) =
let rec step x i =
if i >= 100 then x
else step (x - alpha*(f' x)) (i+1)
step x0 0
。。。但在alpha*(f'x)它仍然告诉我:
“此构造导致代码不像
类型批注。类型变量“a”已被约束为类型
“浮动”
。。这将产生与上述相同的全浮点类型签名。看起来(*)是经过特殊处理的。将代码更改为以下格式:
let inline fmingd (f':^a -> ^a) (x0:^a) (alpha:float) : ^a
when ^a : (static member times : float * ^a -> ^a) and
^a : (static member ( - ) : ^a * ^a -> ^a) =
let rec step x i =
if i >= 100 then x
else step (x - (^a : (static member times : float * ^a -> ^a) (alpha, f' x))) (i+1)
step x0 0
然后当我试着这样做的时候:
let inline fmingd (f':^a -> ^a) (x0:^a) (alpha:float) : ^a
when ^a : (static member ( * ) : float * ^a -> ^a) and
^a : (static member ( - ) : ^a * ^a -> ^a) =
let rec step x i =
if i >= 100 then x
else step (x - (^a : (static member ( * ): float * ^a -> ^a) (alpha, f' x))) (i+1)
step x0 0
我回到了你最初的错误,但也得到了这个错误:
名为“op#u Multiply”的成员约束由F#编译器赋予特殊状态,因为某些.NET类型隐式地增加了该成员。如果试图从自己的代码中调用成员约束,则可能会导致运行时失败
不幸的是,我不确定如果您想使用其他人的类型,那么调用所需的成员times
是否会对您太有效
编辑:
我想这可能是因为
14.5.4.1构件约束解决方案的模拟
假定某些类型隐式定义静态成员,即使类型的实际CLI元数据没有定义这些运算符。该机制用于实现F#库的可扩展转换和数学函数,包括sin、cos、int、float、(+)和(-)。下表显示了为各种类型隐式定义的静态成员
它接着提到了float
,它是有op\u Multiply
(即(*)
)专门定义的事物之一。看起来(*)是经过特殊处理的。将代码更改为以下格式:
let inline fmingd (f':^a -> ^a) (x0:^a) (alpha:float) : ^a
when ^a : (static member times : float * ^a -> ^a) and
^a : (static member ( - ) : ^a * ^a -> ^a) =
let rec step x i =
if i >= 100 then x
else step (x - (^a : (static member times : float * ^a -> ^a) (alpha, f' x))) (i+1)
step x0 0
然后当我试着这样做的时候:
let inline fmingd (f':^a -> ^a) (x0:^a) (alpha:float) : ^a
when ^a : (static member ( * ) : float * ^a -> ^a) and
^a : (static member ( - ) : ^a * ^a -> ^a) =
let rec step x i =
if i >= 100 then x
else step (x - (^a : (static member ( * ): float * ^a -> ^a) (alpha, f' x))) (i+1)
step x0 0
我回到了你最初的错误,但也得到了这个错误:
名为“op#u Multiply”的成员约束由F#编译器赋予特殊状态,因为某些.NET类型隐式地增加了该成员。如果试图从自己的代码中调用成员约束,则可能会导致运行时失败
不幸的是,我不确定如果您想使用其他人的类型,那么调用所需的成员times
是否会对您太有效
编辑:
我想这可能是因为
14.5.4.1构件约束解决方案的模拟
假定某些类型隐式定义静态成员,即使类型的实际CLI元数据没有定义这些运算符。该机制用于实现F#库的可扩展转换和数学函数,包括sin、cos、int、float、(+)和(-)。下表显示了为各种类型隐式定义的静态成员
它接着提到了
float
,它是专门定义的op\u Multiply
(即(*)
)的东西之一。正如编译器指出的,问题在于这个片段:alpha*(f'x)
这是因为alpha是一个浮点
,在f#中,乘法具有一个浮点
,因为第一个操作数期望另一个浮点
,所以它推断第二个操作数为浮点
如果第二个操作数不是泛型的,即:int,您可以使用如下显式转换:int alpha*(f'x)
,但无法表示对f#中泛型类型的泛型op_explicit
的调用,您可以尝试使用成员约束,但Ganesh在F#spec中指出的相同问题也适用于op#u Explicit
我在过去尝试模拟Haskell的通用数学时遇到了同样的问题,特别是通用函数fromInteger
,但是,您可以使用相同的技术创建一个通用fromFloat
函数,或者使用一个通用convert
函数,就像我刚才添加到的函数一样
示例代码:
#r @"FsControl.Core.dll"
#r @"FSharpPlus.dll"
open FSharpPlus
let inline fmingd (f':^a -> ^a) (x0:^a) (alpha:float) : ^a =
let rec step x i =
if i >= 100 then x
else step (x - convert alpha * (f' x)) (i+1)
step x0 0
正如编译器所指出的,问题在于这个片段:
alpha*(f'x)
这是因为alpha是一个浮点
,在f#中,乘法具有一个浮点
,因为第一个操作数期望另一个浮点
,所以它推断第二个操作数为浮点
如果第二个操作数不是泛型的,即:int,您可以使用如下显式转换:int alpha*(f'x)
,但无法表示对f#中泛型类型的泛型op_explicit
的调用,您可以尝试使用成员约束,但Ganesh在F#spec中指出的相同问题也适用于op#u Explicit
我在过去尝试模拟Haskell的通用数学时遇到了同样的问题,特别是通用函数fromInteger
,但是,您可以使用相同的技术创建一个通用fromFloat
函数,或者使用一个通用convert
函数,就像我刚才添加到的函数一样
示例代码:
#r @"FsControl.Core.dll"
#r @"FSharpPlus.dll"
open FSharpPlus
let inline fmingd (f':^a -> ^a) (x0:^a) (alpha:float) : ^a =
let rec step x i =
if i >= 100 then x
else step (x - convert alpha * (f' x)) (i+1)
step x0 0