0

I'm using the below bit of code

// Neat method of finding the TryParse method for any type that supports it.
// See https://stackoverflow.com/a/33161245/158285
let inline tryParseWithDefault (defaultVal:'a) text : ^a when ^a : (static member TryParse : string * ^a byref -> bool) = 
    let r = ref defaultVal
    if (^a : (static member TryParse: string * ^a byref -> bool) (text, &r.contents)) 
    then !r 
    else defaultVal  

but I notice that the type constraint

^a : (static member TryParse : string * ^a byref -> bool

is used twice. Is there any way to do the following

constraint Parsable a = ( a : ^a : (static member TryParse : string * ^a byref -> bool)

and use Parsable like

// Neat method of finding the TryParse method for any type that supports it.
// See https://stackoverflow.com/a/33161245/158285
let inline tryParseWithDefault (defaultVal:'a) text : Parsable = 
    let r = ref defaultVal
    if (^a : (Parsable) (text, &r.contents)) 
    then !r 
    else defaultVal  
bradgonesurfing
  • 30,949
  • 17
  • 114
  • 217

2 Answers2

1

There is no way I know of, however, you can simplify the function by letting F# infer the signature:

let inline tryParseWithDefault defaultVal text = 
    let r = ref defaultVal
    if (^a : (static member TryParse: string * ^a byref -> bool) (text, &r.contents)) 
    then !r 
    else defaultVal
CaringDev
  • 8,391
  • 1
  • 24
  • 43
1

As the existing answer says, you do not explicitly need to repeat the constraint in the type signature because the F# compiler can infer it. One more way of further factoring out the code that involves the type constraint would be to just have tryParse function which invokes the TryParse method (and has the type constraint) and then call this function from your tryParseWithDefault.

This way, you separate the "core" logic of invoking the member from any extra logic. When you do this, you again don't need to repeat the constraint, because the compiler infers it:

let inline tryParse text = 
    let mutable r = Unchecked.defaultof<_>
    (^a : (static member TryParse: string * ^a byref -> bool) (text, &r)), r 

let inline tryParseWithDefault (defaultVal:'a) text =
    match tryParse text with 
    | true, v -> v
    | _ -> defaultVal
Tomas Petricek
  • 240,744
  • 19
  • 378
  • 553
  • I guess this is the best that can be done then at the moment. A pity that type constraints can't be factored out and put into named groups that can be applied later. Kind of reminds me of C++20 concepts. I've added a follow up question to this that develops the above code further but runs into different problems. https://stackoverflow.com/questions/58407301/can-i-rewrite-this-code-to-avoid-the-f-error – bradgonesurfing Oct 16 '19 at 06:51