是否可以在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
给出以下错误:
FS0043 Expecting a type supporting the operator '>=>' but given a function type. You may be missing an argument to a function.
答案 0 :(得分:6)
它不起作用,因为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 }
然后,您可以在全球范围内重新定义>=>
:
let inline (>=>) x y = (Unchecked.defaultof<Ops> >=> y) x
但现在你会发现传递了错误的参数,f必须是AsyncResult<_,_>
类型,因为我不熟悉棋子我将使用虚拟函数:
let f x = Unchecked.defaultof<AsyncResult<int,int>>
let g x = fail x
现在再详细一点,为避免价值限制,您必须在双方添加x
:
let z x = (f >=> g) x
这样可行,但我强烈建议您不要使用此设计。
如果你问我,特别是在全球范围内,超载必须遵循一些规则才能保持一致。这种Ad-hoc重载设计a-la C#不能很好地添加更多东西,很快就会遇到类型推断不知道你想做什么的情况,甚至是你的读者代码。
如果您想使用通用(且表现良好)>=>
,请查看F#+