非惯用的全局运算符重载如何工作?
How does non idiomatic global operator overloading work?
我想了解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
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 不会抱怨它
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
您的第二个示例不起作用,因为 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的Discriminated Union,所以它总是会成功,而且case的名字和类型的名字是一样的。所有这些都是为了缩短代码量,因为 DU 是一个虚拟类型。如果它令人困惑,这里有一个正常的例子 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
您的第三个示例不起作用,因为 (!!)
是一元运算符,而不是像 ($)
这样的二元运算符
有关此旧技术的更多信息,请参见 this old blog。
我想了解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
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 不会抱怨它
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
您的第二个示例不起作用,因为 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的Discriminated Union,所以它总是会成功,而且case的名字和类型的名字是一样的。所有这些都是为了缩短代码量,因为 DU 是一个虚拟类型。如果它令人困惑,这里有一个正常的例子 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
您的第三个示例不起作用,因为 (!!)
是一元运算符,而不是像 ($)
有关此旧技术的更多信息,请参见 this old blog。