2016-06-28 73 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