2011-01-11 32 views
7

圍繞F#成員的約束功能的一些遊戲和寫作之類的函數在這之後:F#成員限制+ ^一按地址參數

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

這工作完全正常:

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

我想寫其他func tryParse,它使用靜態方法TryParse,並將解析結果包裝爲'a option類型,以便在F#中提供更好的支持。這樣的事情並不編譯:

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 

的錯誤是:

錯誤FS0001:是 預計這種表達有型 按地址<「一>但這裏的類型爲 'a ref

F#ref -cells d不工作太:

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 

我做錯了什麼?

+0

哎呀,我想這是一個錯誤......另外,`TryParse:string - > bool *^a`不起作用。 – 2011-01-11 14:02:58

+0

這似乎在F#3.0中得到修復。 – kvb 2012-09-28 18:49:03

回答

4

UPDATE

這似乎是固定在F#3.0。

老答案:

我與斯蒂芬的評論,它是最有可能的一個bug同意。 byref類型有很多限制,所以對於我們來說,他們不適合使用成員約束並不令人驚訝。這是一個(醜)解決方法使用反射:

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

我認爲這也是一個bug,有成員約束和byref類型的東西。

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 

這一個是非常接近:我可以通過改變成員約束的簽名做一個稍微不那麼難看的反射版本

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 

但我得到一個錯誤FS0421:的地址當我嘗試編譯它時,變量'x'在這一點上不能使用

1

這將編譯但仍不能按預期工作:在這種特殊情況下

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> 

,而不是使用反射,我只想重新創建的TryParse瞭解析的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>