首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >op_addition的静态成员约束

op_addition的静态成员约束
EN

Stack Overflow用户
提问于 2016-08-01 14:41:51
回答 3查看 461关注 0票数 3

为了学习,我尝试重新发明List.foldList.reduceList.sum,使用无点的inline函数。以下是我所拥有的:

代码语言:javascript
复制
let flip f y x = f x y

let rec fold folder seed = function
    | [] -> seed
    | h :: t -> fold folder (folder seed h) t

let inline reduce< ^a when ^a : (static member Zero : ^a) > : 
    (^a -> ^a -> ^a) -> ^a list -> ^a =
    flip fold LanguagePrimitives.GenericZero

let inline sum< ^a when 
            ^a : (static member (+) : ^a * ^a -> ^a) and 
            ^a : (static member Zero : ^a)> : ^a list -> ^a = 
    reduce (+)
           // ^ Compile error here

我知道这种冗长的类型约束在F#中并不经常使用,但是我正在努力学习,所以请容忍我。

我收到了一个非常神秘的编译错误,我不明白:

代码语言:javascript
复制
Type mismatch. Expecting a
    'a -> 'a -> 'a 
but given a
    'a -> 'b -> 'c     
A type parameter is missing a constraint 'when ( ^a or  ^?269978) : (static member ( + ) :  ^a *  ^?269978 ->  ^?269979)' 
A type parameter is missing a constraint 'when ( ^a or  ^?269978) : (static member ( + ) :  ^a *  ^?269978 ->  ^?269979)' 
val ( + ) : x:'T1 -> y:'T2 -> 'T3 (requires member ( + )) 
Full name: Microsoft.FSharp.Core.Operators.( + ) 
Overloaded addition operator
x: The first parameter. 
y: The second parameter.

我应该添加什么来满足编译器?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-08-01 16:17:34

我不知道一种完全按照您的要求执行的方法,因为我不知道如何以无切入点的方式调用静态约束的静态成员。请注意,您没有调用(+) of ^a,编译器也不知道如何解决这个问题.如果您乐于使用内部助手函数,则可以:

代码语言:javascript
复制
let inline sum< ^a
    when ^a : (static member (+) : ^a -> ^a -> ^a) and
         ^a : (static member Zero : ^a) > : ^a list -> ^a =
    let add x y = (^a : (static member (+) : ^a -> ^a -> ^a) (x, y))
    reduce add

注意警告

警告FS0077:名为“op_Addition”的成员约束由F#编译器给出特殊状态,因为某些.NET类型是通过该成员隐式增强的。如果尝试从自己的代码中调用成员约束,这可能导致运行时失败。

事实上:

sum [1; 2; 3]导致

System.NotSupportedException:不支持指定的方法。 .=‘Int32 1’>(Int32 x,Int32 y)在.

但是,如果将sum更改为:

代码语言:javascript
复制
let inline sum list =
    reduce (+) list

sum [1; 2; 3] // 6
票数 3
EN

Stack Overflow用户

发布于 2016-08-01 16:57:01

我无济于事的回答是:不要那样做。内联定义只用于语法功能,因此不应该以无点的方式定义它们。例如,比较尝试评估以下三行的结果:

代码语言:javascript
复制
let inline identity = id
let inline identity : ^a -> ^a = id
let inline identity< ^a> : ^a -> ^a = id

只有最后一个函数进行编译(从技术上讲,这是因为它是一个“类型函数”,基本上是一个函数,它在幕后传递一个不可见的unit值,允许将其作为泛型值处理)。

但是,如果您坚持这样做,那么“修复”的一种方法就是降低(+)的泛型;默认情况下,参数和返回类型可以是不同的类型,这种灵活性带来的约束是使编译器感到困惑的部分原因。这里有一个解决办法:

代码语言:javascript
复制
let inline reduce< ^a, 'b  when  ^a : (static member Zero : ^a)> : ( ^a -> 'b ->  ^a) -> ('b list ->  ^a) =
    flip fold LanguagePrimitives.GenericZero

let inline (+) (x:^a) (y:^a) = x + y

let inline sum< ^a
                 when ^a : (static member ( + ) :  ^a * ^a -> ^a)
                  and ^a : (static member Zero : ^a)> : ^a list -> ^a =
    reduce (+)
票数 3
EN

Stack Overflow用户

发布于 2016-08-01 16:29:18

就像Vandroiy一样,给定的减值函数不会为我编译。我认为您想要的reduce函数实际上是:

代码语言:javascript
复制
let inline reduce< ^a when ^a : (static member Zero : ^a) > : ((^a -> ^a -> ^a) -> ^a list -> ^a)  =
    flip fold LanguagePrimitives.GenericZero

这样我就能复制出你的错误了。

但是,当我通过使用简单的测试函数将sum函数更改为编译时:

代码语言:javascript
复制
let inline sum< ^a when 
        ^a : (static member Zero : ^a) and
        ^a : (static member (+) : (^a -> ^a -> ^a))  > : ^a list -> ^a = 
    reduce (fun i j -> i)

并试图在sum [1..10]中调用The type 'int' does not support the operator 'get_op_Addition'结果。所以我不确定这个方法会不会起作用。

编辑:谢谢CaringDev的提示,我修复了get_op_Addition错误。这似乎很管用。至于为什么,我很困惑,因为'b只是伪装的^a .

代码语言:javascript
复制
let inline sum< ^a when 
        ^a : (static member Zero : ^a) and
        ^a : (static member (+) : ^a -> ^a -> ^a)  > : ^a list -> ^a =
    let inline add (x:'b) (y:'b) = (+) x y
    reduce add
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38701715

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档