是否可以在F#中重载操作符,其中操作数是函数?
例如(使用Chessie):
module AsyncTrialOperators =
type Ops=
/// Left-to-right Kleisli composition
static member (>=>) (f:'a -> AsyncResult<'b,_>, g:'b -> AsyncResult<'c,_>) =
fun x ->
asyncTrial {
let! y = f x
let! z = g y
return z }
/// Left-to-right Kleisli composition
static member (>=>) (f:'a -> AsyncResult<'b,_>, g:'b -> Result<'c,_>) =
fun x ->
asyncTrial {
let! y = f x
let! z = g y
return z }
// Example usage (doesn't compile)
let f x = ok x
let g x = fail x
let z = f >=> g
Run Code Online (Sandbox Code Playgroud)
给出以下错误:
FS0043 Expecting a type supporting the operator '>=>' but given a function type. You may be missing an argument to a function.
它不起作用,因为Ops它不是参数的一部分.
您可以使用将其中一个参数移动到lambda的技巧,然后使用vacant参数接收容器类型的伪参数:
#r @"c:\packages\chessie.0.6.0\lib\net40\Chessie.dll"
open Chessie
open Chessie.ErrorHandling
type Ops=
/// Left-to-right Kleisli composition
static member (>=>) (_:Ops, g:'b -> Result<'c,_>) =
fun (f:'a -> AsyncResult<'b,_>) x ->
asyncTrial {
let! y = f x
let! z = g y
return z }
/// Left-to-right Kleisli composition
static member (>=>) (_:Ops, g:'b -> AsyncResult<'c,_>) =
fun (f:'a -> AsyncResult<'b,_>) x ->
asyncTrial {
let! y = f x
let! z = g y
return z }
Run Code Online (Sandbox Code Playgroud)
然后,您可以>=>在全球范围内重新定义:
let inline (>=>) x y = (Unchecked.defaultof<Ops> >=> y) x
Run Code Online (Sandbox Code Playgroud)
但是现在你会意识到传递错误的参数,f必须是类型的AsyncResult<_,_>,因为我不熟悉棋子我将使用虚拟函数:
let f x = Unchecked.defaultof<AsyncResult<int,int>>
let g x = fail x
Run Code Online (Sandbox Code Playgroud)
现在再详细一点,为了避免价值限制,你必须x在双方添加:
let z x = (f >=> g) x
Run Code Online (Sandbox Code Playgroud)
这样可行,但我强烈建议您不要使用此设计.
如果你问我,特别是在全球范围内,超载必须遵循一些规则才能保持一致.这种Ad-hoc重载设计a-la C#不能很好地添加更多东西,很快就会遇到类型推断不知道你想做什么的情况,甚至是你的读者码.
如果你想使用泛型(并且表现良好),请>=>查看F#+中定义的那个