2017-10-17 3 views
3

ich den folgenden CodeWie zu verwandeln OO ruft eine einige generische Funktion ruft in

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} 

, die perfekt funktioniert, wenn ich es so nennen sich mit den normalen OO-Notation haben.

printfn "100 %s" (Shows().GetShow("some").Show("some")) 

Allerdings würde Ich mag, dass in eine Funktion wickeln, so dass

let inline show x = (Shows().GetShow(x).Show(x)) 

Aber das gibt mir die folgenden Fehler

[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> 

Irgendwelche Ideen, wie dies zu überwinden?

Antwort

3

Kommt Ihnen das nahe genug an das, was Sie wollen?

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 

Es ist nicht zu hart, wenn Sie Ihre Shows außerhalb der Inline-Funktion erstellen. Auf diese Weise müssen die Methoden nicht inline sein.

2

Sie müssen statisch aufgelöste Typparameter verwenden und explizit angeben, dass der Typ ein GetShow Member mit der erforderlichen Signatur haben soll. Dies funktioniert auch nur mit statischen Mitgliedern.

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) 

die Einschränkung in einem separaten Betreiber Wrapping up $ notwendig ist, da Sie nur statisch Einschränkungen für Typparameter aufgelöst angeben können - also nicht so etwas wie (when Show : (member ...)) sagen kann, können die konkreten Typ nicht verwenden Show in Da muss ein Parameter sein. Also führen wir eine Zwischenfunktion $ ein und rufen sie dann mit Show als Parameter auf.

Und der Grund, warum ich einen Operator $ anstelle einer regulären Funktion verwende, ist, dass statisch aufgelöste Constraints für Operatoren abgeleitet werden. Bei einer normalen Funktion müssten Sie die when ...-Klausel zweimal schreiben - einmal in der Signatur, einmal im Text.

Verwandte Themen