Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
574 views
in Technique[技术] by (71.8m points)

generics - F# member constraints + ^a byref parameters

After some playing around F# member constraints feature and writing function like this:

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

That works perfectly fine:

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

I'm trying to write other func tryParse, that uses static method TryParse and wraps the parse result into 'a option type for better support in F#. Something like this doesn't compiles:

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

The error is:

error FS0001: This expression was expected to have type byref<'a> but here has type 'a ref

F# ref-cells doesn't work too:

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

What am I doing wrong?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

UPDATE

This appears to be fixed in F# 3.0.

Old answer:

I agree with Stephen's comment that it's most likely a bug. There are many limitations on byref types, so it's not particularly surprising to me that they don't play well with member constraints. Here's an (ugly) workaround using reflection:

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"

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...