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

use*_*963 3 f# overloading operator-overloading operators

我想了解这个答案的代码

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
Run Code Online (Sandbox Code Playgroud)

F#可以解决重载成员.(因为它不支持成员的currying).所以,我认为,它也适用于方法

但它没有:

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
Run Code Online (Sandbox Code Playgroud)

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

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

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
Run Code Online (Sandbox Code Playgroud)

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

Gus*_*Gus 6

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

所以是的,它是可能的,但您必须手动编写约束,编译器不会为您推断它们:

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
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

你的第三个例子不起作用,因为它(!!)是一元运算符,而不是二进制运算符($)

这个旧博客中有关这种旧技术的更多信息.