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

时间:2016-06-03 07:03:43

标签: f# operator-overloading operators overloading

我想了解this回答

中的代码
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#可以解决重载的成员。 (因为它不支持成员的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
  

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

定义运算符$的语法令人困惑。它接受大写标识符作为运算符的第一个参数,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
  

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

1 个答案:

答案 0 :(得分: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

您提到的大写标识符只匹配一个案例的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

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

this old blog中有关此旧技术的更多信息。