内联时扩展方法出错

rob*_*kuz 4 f#

我想扩展一些系统类型,然后通过内联使用它们

type System.String with  
    member this.foo n = this + "!" + n 

type System.Boolean with  
    member this.foo n = sprintf "%A!%A" this n 
Run Code Online (Sandbox Code Playgroud)

现在我调用这些扩展方法

let x = "foo".foo "bar"
let y = true.foo "bar"
Run Code Online (Sandbox Code Playgroud)

这给了我这个

- val x : System.String = "foobar"
- val y : string = "true!"bar""
Run Code Online (Sandbox Code Playgroud)

所有罚款和花花公子 - 但现在我想将调用包装.foo成内联函数

let inline foo n v = (^T : (member foo : ^N  -> ^S) v, n)
let z = foo "bar" "baz" 
Run Code Online (Sandbox Code Playgroud)

只是现在我收到编译错误告诉我

> The type 'string' does not support the operator 'foo':
Run Code Online (Sandbox Code Playgroud)

嗯......确实如此!

有人可以解释一下吗?

Gus*_*Gus 9

静态成员约束中不考虑扩展方法(可能与重复),当您希望使用成员约束实现通用代码并使其也适用于已定义或基本类型时,这是一个普遍问题.

查看用户语音请求,以及此处提到的变通方法以及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"
Run Code Online (Sandbox Code Playgroud)

您可以通过为新类型添加显式泛型重载来增强它:

// 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"
Run Code Online (Sandbox Code Playgroud)

您可以通过手动编写静态约束并使用成员而不是运算符来进一步优化它(请参阅此处的示例),

在一天结束时,您将最终得到类似FsControl的通用追加功能.