Reputation: 9924
I have the following code
type Show<'a> =
abstract member Show: 'a -> string
type Shows() =
member inline this.GetShow(x:string) =
{new Show<string> with member this.Show(x:string) = x}
member inline this.GetShow(x:int) =
{new Show<int> with member this.Show(x:int) = sprintf "%A" x}
which works perfectly if I call it using normal OO notation.
printfn "100 %s" (Shows().GetShow("some").Show("some"))
However I'd like to wrap that into a function so that
let inline show x = (Shows().GetShow(x).Show(x))
But this gives me the following error
[FS0041] A unique overload for method 'GetShow' could not be determined based
on type information prior to this program point. A type annotation may be
needed. Candidates:
member Shows.GetShow : x:int -> Show<int>,
member Shows.GetShow : x:string -> Show<string>
Any ideas how to overcome this?
Upvotes: 3
Views: 72
Reputation: 10624
Does this get you close enough to what you want?
let inline GetShow p x = (^x : (member GetShow : ^p -> ^o) (x, p))
let inline Show p x = (^x : (member Show : ^p -> ^o) (x, p))
let inline show x s = s |> GetShow x |> Show x
Shows() |> show "a"
Shows() |> show 1
It's not too hard if you create your Shows
outside of the inline function. This way the methods don't need to be inline.
Upvotes: 3
Reputation: 80744
You have to use statically resolved type parameters and explicitly state that you expect the type to have a GetShow
member with the required signature. Also, this only works with static members.
type Shows() =
static member inline GetShow(x:string) =
{new Show<string> with member this.Show(x:string) = x}
static member inline GetShow(x:int) =
{new Show<int> with member this.Show(x:int) = sprintf "%A" x}
let inline ($) (a: ^a) (b: ^b) =
((^a or ^b): (static member GetShow : ^b -> Show< ^b>) b)
let inline show x = (Shows() $ x).Show(x)
Wrapping up the constraint in a separate operator $
is necessary, because you can only specify statically resolved constraints on type parameters - i.e. you can't say something like (when Show : (member ...))
, can't use the concrete type Show
in there, has to be a parameter. So we introduce an intermediate function $
and then call it with Show
as parameter.
And the reason I use an operator $
instead of a regular function is that statically resolved constraints get inferred for operators. With a regular function, you'd have to write the when ...
clause twice - once in the signature, once in the body.
Upvotes: 2