F#成员约束+ ^ a byref参数

con*_*low 8 generics f# constraints ref byref

在玩了一些F#成员约束功能并编写如下函数之后:

let inline parse< ^a when ^a : (static member Parse: string -> ^a) > s =
    (^a: (static member Parse: string -> ^a) s)
Run Code Online (Sandbox Code Playgroud)

这很好用:

let xs = [ "123"; "456"; "999" ] |> List.map parse<int>
Run Code Online (Sandbox Code Playgroud)

我正在尝试编写其他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
Run Code Online (Sandbox Code Playgroud)

错误是:

错误FS0001:此表达式的类型为 byref <'a>, 但此处的类型为 "a ref"

F#ref-cells也不起作用:

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
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?

kvb*_*kvb 5

更新

这似乎已在F#3.0中修复。

旧答案:

我同意Stephen的评论,即最有可能是错误。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"
Run Code Online (Sandbox Code Playgroud)