非惯用的全局运算符重载如何工作? [英] How does non idiomatic global operator overloading work?

查看:72
本文介绍了非惯用的全局运算符重载如何工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想了解答案中的代码

type Mult = Mult with
    static member inline ($) (Mult, v1: 'a list) = fun (v2: 'b list) -> 
        v1 |> List.collect (fun x -> v2 |> List.map (fun y -> (x, y))) : list<'a * 'b>
    static member inline ($) (Mult, v1:'a      ) = fun (v2:'a) -> v1 * v2 :'a

let inline (*) v1 v2 = (Mult $ v1) v2

F#可以解析过载的成员. (因为它不支持成员诅咒).所以,我想,它也应该适用于方法

F# can resolve overloaded members. (Because it doesn't support currying of members). So, I supposed, it should work for methods as well

但不是:

type Mult = Mult with
        static member inline Do (Mult, v1: 'a list) = fun (v2: 'b list) -> 
            v1 |> List.collect (fun x -> v2 |> List.map (fun y -> (x, y))) : list<'a * 'b>
        static member inline Do (Mult, v1:'a      ) = fun (v2:'a) -> v1 * v2 :'a
    let inline (<.>) v1 v2 = (Mult.Do (Mult,v1)) v2

无法基于以下方法确定方法"Do"的唯一重载 在此程序点之前输入类型信息.类型注释可能是 需要.候选人:静态成员Mult.Do:Mult:Mult * v1:^ a->(^ a -> ^ a)当^ a:(静态成员(*):^ a * ^ a-> ^ a),静态成员Mult.Do:Mult:Mult * v1:'a list->('b list-> ('a *'b) 列表)

A unique overload for method 'Do' could not be determined based on type information prior to this program point. A type annotation may be needed. Candidates: static member Mult.Do : Mult:Mult * v1: ^a -> ( ^a -> ^a) when ^a : (static member ( * ) : ^a * ^a -> ^a), static member Mult.Do : Mult:Mult * v1:'a list -> ('b list -> ('a * 'b) list)

定义运算符$的语法令人困惑.它接受大写标识符作为运算符的第一个参数,Visual Studio不会抱怨它

The syntax in which operator $ is defined is confusing. It accepts upper case identifier as first argument of operator and Visual Studio doesn't complain about it

推断出Mult是Mult类型,但是令人惊讶的是,这不起作用:

Mult is inferred to be of type mult, but surprisingly this doesn't work:

type Mult = Mult with
    static member inline (!!) (mlt:Mult, v1: 'a list) = fun (v2: 'b list) -> 
        v1 |> List.collect (fun x -> v2 |> List.map (fun y -> (x, y))) : list<'a * 'b>
    static member inline (!!) (mlt:Mult, v1:'a      ) = fun (v2:'a) -> v1 * v2 :'a

let inline (<!>) v1 v2 = (Mult !! v1) v2

错误FS0003:此值不是函数,无法应用

error FS0003: This value is not a function and cannot be applied

推荐答案

您的第二个示例不起作用,因为F#不会像操作符那样自动推断方法的静态成员约束.

Your second example doesn't work because F# doesn't automatically infer static member constraints with methods as it does with operators.

是的,有可能,但是您将不得不手动编写约束,编译器不会为您推断它们:

So yes, it's possible but you will have to write the constraints by hand, the compiler will not infer them for you:

type Mult = Mult with
    static member inline Do (Mult, v1: 'a list) = fun (v2: 'b list) -> 
        v1 |> List.collect (fun x -> v2 |> List.map (fun y -> (x, y))) : list<'a * 'b>
    static member inline Do (Mult, v1:'a      ) = fun (v2:'a) -> v1 * v2 :'a

let inline impl m v1 v2 = ((^T or ^a) : (static member Do:^T* ^a->(^b-> ^c)) (m,v1)) v2
let inline (<.>) a b = impl Mult a b

您提到的大写标识符仅与一个个案的Distributed Union匹配,因此它将始终成功,并且个案名称与该类型的名称相同.所有这些都是为了缩短代码量,因为DU是伪类型.如果令人困惑,下面是一个带有普通类的示例:

The upper-case identifier you mentioned is matching a Discriminated Union of only one single case, so it will always succeed and the name of the case is the same name of the type. All this is to shorten just a bit the amount of code since that DU is a dummy type. If it's confusing here's an example with a normal class:

type Mult() = class end with
    static member inline ($) (_:Mult, v1: 'a list) = fun (v2: 'b list) -> 
        v1 |> List.collect (fun x -> v2 |> List.map (fun y -> (x, y))) : list<'a * 'b>
    static member inline ($) (_:Mult, v1:'a      ) = fun (v2:'a) -> v1 * v2 :'a

let inline (*) v1 v2 = (Mult() $ v1) v2

您的第三个示例不起作用,因为(!!)是一元运算符,而不是像($)

Your third example doesn't work because (!!) is an unary operator, not binary like ($)

此旧博客.

这篇关于非惯用的全局运算符重载如何工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆