简体   繁体   English

非惯用全局运算符重载如何工作?

[英]How does non idiomatic global operator overloading work?

I want to understand the code from this answer 我想了解这个答案的代码

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# can resolve overloaded members. F#可以解决重载的成员。 (Because it doesn't support currying of members). (因为它不支持成员的currying)。 So, I supposed, it should work for methods as well 所以,我认为,它也适用于方法

But it doesn't: 但它没有:

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

A unique overload for method 'Do' could not be determined based on type information prior to this program point. 根据此程序点之前的类型信息,无法确定方法“Do”的唯一重载。 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) 候选人:静态成员Mult.Do:Mult:Mult * v1:^ a - >(^ a - > ^ a)当^ a :(静态成员(*):^ a * ^ a - > ^ a),静态成员Mult.Do:Mult:Mult * v1:'a list - >('b list - >('a *'b)list)

The syntax in which operator $ is defined is confusing. 定义operator $的语法令人困惑。 It accepts upper case identifier as first argument of operator and Visual Studio doesn't complain about it 它接受大写标识符作为运算符的第一个参数,Visual Studio不会抱怨它

Mult is inferred to be of type mult, but surprisingly this doesn't work: Mult被推断为mult类型,但令人惊讶的是这不起作用:

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

error FS0003: This value is not a function and cannot be applied 错误FS0003:该值不是函数,无法应用

Your second example doesn't work because F# doesn't automatically infer static member constraints with methods as it does with operators. 您的第二个示例不起作用,因为F#不会像使用运算符一样使用方法自动推断静态成员约束。

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

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. 您提到的大写标识符只匹配一个案例的Discriminated Union,因此它将始终成功,并且案例的名称与该类型的名称相同。 All this is to shorten just a bit the amount of code since that DU is a dummy type. 所有这些都是为了缩短代码量,因为DU是虚拟类型。 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 ($) 你的第三个例子不起作用,因为(!!)是一元运算符,而非二进制像($)

More information about this old technique in this old blog . 这个旧博客中有关这种旧技术的更多信息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM