Error in extension methods when embedding

I want to expand some types of systems and then use them with inlining

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

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

Now i call these extension methods

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

which gives me this

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

Everything is beautiful and dandy - but now I want to associate the call .foowith a built-in function

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

Only now I get a compiler error telling me that

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

well ... he does!

Can someone explain what is happening?

+4
source share
2 answers

Extension methods are not taken into account in member static constraints (a possible duplicate of this ), and this is a common problem when you want to implement common code using member constraints and make it work with already defined or primitive types as well.

. , , , 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"

, (. ),

- generic append FsControl.

+9

. F #.

, F # , .

+2

All Articles