2016-06-28 53 views
4

时,我想延长一些系统类型和以后通过内联使用它们错误的扩展方法内联

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

type System.Boolean with 
    member this.foo n = sprintf "%A!%A" this n 

现在我把这些扩展方法

let x = "foo".foo "bar" 
let y = true.foo "bar" 

这给了我这个

- val x : System.String = "foobar" 
- val y : string = "true!"bar"" 

所有罚款和花花公子 - 但现在我想调用.foo包装成一个内联˚F结

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

只有现在我得到一个编译错误告诉我,

> The type 'string' does not support the operator 'foo': 

以及...它!

有人能解释一下怎么回事?

回答

9

在静态成员约束中不考虑扩展方法(可能重复的this),当您想使用成员约束实现泛型代码并使其与已定义或基本类型一起工作时,这是一个普遍问题。

请参阅user voice请求,以及提及的解决方法hereDon Syme's explanation of why it's complicated to implement it in the F# compiler

如果按照链接在那里你会看到目前要解决它主要包括创建所有已知类型的中间型和重载和通用一个用于扩展的方式。

这是如何解决办法这是一个非常简单的例子:

// 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" 

您可以进一步完善了它:

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" 

您可以通过添加新类型明确的泛型重载提升它手动编写静态约束并使用成员而不是操作员(请参阅示例here),

在一天结束时,您最终将像从FsControl这个generic append功能。

2

静态解析的类型约束不支持扩展方法。这仅仅是F#的一个功能。

如果您想F#获得了kinded高多态性的支持,可以vote for it on user voice