Let's assume I'm constructing an F# generic function f
with a single argument integral
, and this argument by the function semantics should be constrained to any .NET integral type from System.SByte
through System.Int32
to System.Numerics.BigInteger
.
One approach would be implementing
let inline f (integral: 'a) =
(* function body here *) ...
and rely on compiler-deduced constraints to 'a
derived from the actual contents of f
's body, which may or may not coincide with the set of integral .NET
types.
Another approach might be to force explicit hand-picked a priori constraints to 'a
that would really guarantee for known .NET types that only integral types pass the static
check, for example
let inline f (integral: ^a when ^a:(static member (|||): ^a * ^a-> ^a)) =
(* function body here, unit for illustration *)()
or
let inline f< ^a when ^a : (static member (|||): ^a * ^a -> ^a)> (integral: ^a) =
(* function body here, unit for illustration *)()
so f 1uy
, f 1L
, f 1I
pass the static type check right away, but f 'a'
, f 1.0
, f 1m
do not.
What would be benefits, if any, of using second approach over the first?
Are there more idiomatic ways to reach the initial goal?
UPDATE 02/03/2014 Ironically, only today after looking at this answer managed to get a working code out of @kvb's prompt:
let inline implementation integral = ((* whatever implementation here *))
type Integral = Integral with
static member ($) (Integral, value: byte) = implementation value
static member ($) (Integral, value: sbyte) = implementation value
static member ($) (Integral, value: int16) = implementation value
static member ($) (Integral, value: uint16) = implementation value
static member ($) (Integral, value: int) = implementation value
static member ($) (Integral, value: uint32) = implementation value
static member ($) (Integral, value: int64) = implementation value
static member ($) (Integral, value: uint64) = implementation value
static member ($) (Integral, value: bigint) = implementation value
let inline doit integral = Integral $ integral
doit 1
doit 1I
doit 1.0 // does not compile
doit 1.0m // does not compile
doit '1' // does not compile