2011-01-11 14 views
7

Nach einigem Herumspielen F # Mitglied Einschränkungen verfügen und Schreibfunktion wie folgt aus:F # Mitglied Einschränkungen +^a byref Parameter

let inline parse< ^a when ^a : (static member Parse: string -> ^a) > s = 
    (^a: (static member Parse: string -> ^a) s) 

, die perfekt funktioniert gut:

let xs = [ "123"; "456"; "999" ] |> List.map parse<int> 

Ich versuche zu schreiben andere func tryParse, die statische Methode TryParse verwendet und das Parse-Ergebnis in 'a option Typ für bessere Unterstützung in F # umschließt. So etwas wie dies kompiliert nicht:

let inline tryParse s = 
    let mutable x = Unchecked.defaultof< ^a> 
    if (^a: (static member TryParse: string * ^a byref -> bool) (s, &x)) 
     then Some x else None 

Der Fehler ist:

Fehler FS0001: Dieser Ausdruck wurde Typ byref < ‚a> aber hier geben hat zu erwarten 'a ref

F # ref -zellen d funktioniert auch nicht:

let inline tryParse s = 
    let x = ref Unchecked.defaultof< ^a> 
    if (^a: (static member TryParse: string * ^a byref -> bool) (s, x)) 
     then Some x else None 

Was mache ich falsch?

+0

Huch, ich denke, das ist ein Fehler ... auch, 'Tryparse: string -> bool *^a' funktioniert nicht. –

+0

Dies scheint in F # 3.0 behoben zu sein. – kvb

Antwort

4

UPDATE

Dies scheint in F # 3.0 behoben werden.

Alte Antwort:

ich mit Stephen Kommentar darüber einig, dass es sehr wahrscheinlich ein Fehler. Es gibt viele Einschränkungen für ByRef-Typen, daher ist es nicht besonders überraschend, dass sie nicht gut mit Member-Constraints funktionieren. Hier ist eine (hässlich) Abhilfe mit Reflexion:

type parseDel<'a> = delegate of string * 'a byref -> bool 

type Parser< ^a when ^a : (static member TryParse: string * ^a byref -> bool)> private()= 
    static let parser = System.Delegate.CreateDelegate(typeof<parseDel<'a>>, typeof<'a>.GetMethod("TryParse", [|typeof<string>; typeof<'a>.MakeByRefType()|])) :?> parseDel<'a> 
    static member inline ParseDel = parser 

let inline tryParse (s:string) = 
    let mutable x = Unchecked.defaultof< ^a> 
    if Parser<_>.ParseDel.Invoke(s, &x) then 
    Some x 
    else None 

let one : int option = tryParse "1" 
1

Ich denke, dass es ein Fehler ist auch, was mit dem Mitglied Einschränkungen und byref Typen.

let inline tryParse<'a when 'a : (static member TryParse : string -> 'a byref -> bool)> s = 
    let args = [| s ; null |] 
    if typeof<'a> 
     .GetMethod("TryParse", [| typeof<string>; typeof< ^a>.MakeByRefType() |]) 
     .Invoke(null, args) = box true 
     then Some (args.[1] :?> 'a) 
     else None 

Dieser ist ganz in der Nähe:

let inline tryParse< ^a when ^a: (static member TryParse: string -> ^a byref -> bool)> s = 
    let mutable x = Unchecked.defaultof<'a> 
    if (^a: (static member TryParse: string -> ^a byref -> bool) (s, &x)) 
     then Some x else None 

aber ich bekomme einen Fehler FS0421: Die Adresse des I kann durch Änderung der Unterschrift des Mitglieds Constraint eine etwas weniger hässlich Reflexion Version machen Variable 'x' kann zu diesem Zeitpunkt nicht verwendet werden, wenn ich versuche, es zu kompilieren.

1

Dies kompiliert, aber immer noch nicht so funktioniert erwartet:

let inline tryParse< ^a when ^a: (static member TryParse: string -> ^a ref -> bool) > s = 
    let x = ref Unchecked.defaultof< ^a> 
    match (^a: (static member TryParse: string -> ^a ref -> bool) (s, x)) with 
    | false -> None 
    | true -> Some(!x) 

// returns [Some 0; Some 0; Some 0; null], so our tryParse is not retrieving the value from the ref 
let xs = [ "1"; "456"; "999"; "a" ] |> List.map tryParse<int> 

in diesem speziellen Fall, anstatt mithilfe von Reflektion würde ich neu nur TryParse aus Parse in f #

let inline tryParse< ^a when ^a: (static member Parse: string -> ^a) > s = 
    try 
    Some(^a: (static member Parse: string -> ^a) s) 
    with 
    | exn -> None 

let xs = [ "1"; "456"; "999"; "a" ] |> List.map tryParse<int> 
+0

Ich habe dies auf [email protected] angesprochen –