静态成员约束中不考虑扩展方法(可能重复this),当您想要使用成员约束实现泛型代码并使其也适用于已定义的或原始类型时,这是一个普遍问题。
See the 用户声音请求,还有提到的解决方法here and Don Syme 解释了为什么在 F# 编译器中实现它很复杂.
如果您点击那里的链接,您将看到目前的解决方法,它基本上涉及为所有已知类型创建中间类型和重载,以及为扩展创建通用类型。
这是如何解决该问题的一个非常基本的示例:
type Foo = Foo with
static member ($) (Foo, this:int) = fun (n:int) -> this + n
static member ($) (Foo, this:string) = fun n -> this + "!" + n
static member ($) (Foo, this:bool) = fun n -> sprintf "%A!%A" this n
let inline foo this n = (Foo $ this) n
//Now you can create your own types with its implementation of ($) Foo.
type MyType() =
static member ($) (Foo, this) =
fun n -> printfn "You called foo on MyType with n = %A" n; MyType()
let x = foo "hello" "world"
let y = foo true "world"
let z = foo (MyType()) "world"
您可以通过为新类型添加显式泛型重载来增强它:
// define the extensions
type System.String with
member this.foo n = this + "!" + n
type System.Boolean with
member this.foo n = sprintf "%A!%A" this n
// Once finished with the extensions put them in a class
// where the first overload should be the generic version.
type Foo = Foo with
static member inline ($) (Foo, this) = fun n -> (^T : (member foo : ^N -> ^S) this, n)
static member ($) (Foo, this:string) = fun n -> this.foo n
static member ($) (Foo, this:bool) = fun n -> this.foo n
// Add other overloads
static member ($) (Foo, this:int) = fun n -> this + n
let inline foo this n = (Foo $ this) n
//later you can define any type with foo
type MyType() =
member this.foo n = printfn "You called foo on MyType with n = %A" n; MyType()
// and everything will work
let x = foo "hello" "world"
let y = foo true "world"
let z = foo (MyType()) "world"
您可以通过手动编写静态约束并使用成员而不是运算符来进一步完善它(请参阅示例here),
最终你会得到这样的结果通用附加来自 FsControl 的函数。