【问题标题】:How does non idiomatic global operator overloading work?非惯用的全局运算符重载如何工作?
【发布时间】:2016-10-03 03:25:01
【问题描述】:

我想了解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# 可以解析重载成员。 (因为它不支持成员的柯里化)。所以,我想,它也应该适用于方法

但它没有:

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) 列表)

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

【问题讨论】:

    标签: f# operator-overloading operators overloading


    【解决方案1】:

    您的第二个示例不起作用,因为 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
    

    你提到的大写标识符匹配一个只有一个 case 的 Discriminate Union,所以它总是会成功,并且 case 的名称与类型的名称相同。所有这些都是为了缩短代码量,因为 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 中有关此旧技术的更多信息。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-06-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-15
      • 2012-01-25
      相关资源
      最近更新 更多