2011-01-11 4 views
7

После некоторой игры вокруг F имеет ограничение # членов и функция письма, как это:F ограничение # члена +^а ByRef параметров

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

ошибка: Это выражение, как ожидается, иметь тип ByRef < «а>, но здесь имеет тип 'a ref

F # ref-cells d Кроме того, не работает:

Что я делаю неправильно?

+0

Yikes, я думаю, это ошибка ... также, 'TryParse: string -> bool *^a' не работает. –

+0

Это, по-видимому, исправлено в F # 3.0. – kvb

ответ

4

ОБНОВЛЕНИЕ

Это по-видимому, фиксируется в F # 3.0.

Старый ответ:

Я согласен с комментарием Стефана, что это, скорее всего, ошибка. Есть много ограничений на типы 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

Я думаю, что это ошибка тоже что-то с ограничениями членов и 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> 
+0

Я поднял это на [email protected] –

Смежные вопросы