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

того, как вы поиграете в 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>

Я пытаюсь написать другой функционал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 < 'а> но тут есть тип'ссылка

F #ref-клетки тоже не работают:

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

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

 kvb28 сент. 2012 г., 20:49
Похоже, это исправлено в F # 3.0.
 Stephen Swensen11 янв. 2011 г., 15:02
Да, я думаю, что это ошибка ... также,TryParse: string -> bool * ^a не работает

Ответы на вопрос(3)

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 из Parse в 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>
 Paolo Falabella05 февр. 2011 г., 10:34
Я поднял это до [email protected]

что это тоже ошибка, что-то с ограничениями членов и типами 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' нельзя использовать в данный момент когда я пытаюсь скомпилировать это.

Решение Вопроса

ОБНОВИТЬ

Похоже, это исправлено в 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"

Ваш ответ на вопрос