Element constraints F # + ^ a byref parameters

After some reproduction of the membership restriction function F # and recording such a function:

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

This works great:

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

I am trying to write another func tryParse that uses the static tryParse method and transfers the result of the parsing to the 'a option type for better support in F #. Something like this does not compile:

 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 

Mistake:

error FS0001: this expression was the expected type byref <'a> , but there is a type ' a ref

F # ref cells do not work either:

 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?

+7
generics f # constraints ref
Jan 11 '11 at 11:00
source share
3 answers

UPDATE

This seems to be fixed in F # 3.0.

Old answer:

I agree that Stephen comments that this is most likely a mistake. There are many restrictions on byref types, so it’s not particularly surprising to me that they play poorly with member restrictions. Here's a (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" 
+4
Jan 11 2018-11-11T00:
source share
β€” -

I think this is also a mistake, something with member restrictions and byref types. I can make a slightly less ugly version of reflection by changing the element's restriction signature:

 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 

It's very close:

 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 

but I get error message FS0421: the address of the variable 'x' cannot be used at this moment when I try to compile it.

+1
Jan 12
source share

This compiles, but still does not work as expected:

 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> 

in this particular case, instead of using reflection, I would just recreate TryParse from Parse in 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> 
+1
Feb 05 2018-11-11T00:
source share



All Articles