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
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