How to implement automatic generalization in a simple function
I created the following statement to help with safe division.
let (/!) a b =
if b = 0 then 0
else a / b
The problem is that it only works with integers, and I would like this function to work with any numeric primitive (int, float, decimal, etc.).
I've read about automatic generalization but it hasn't quite dived in and I'm not sure if it's even the right direction.
How do you generalize this operator?
Thank,
Joe
source to share
Hi this is a bit of a hidden gem, but what you are looking for is this:
let inline (/!) (a : ^a) (b : ^a) : ^a =
if b = LanguagePrimitives.GenericZero
then LanguagePrimitives.GenericZero
else a / b
btw: it has this monster type:
val inline ( /! ) :
a: ^a -> b: ^a -> ^a
when ^a : equality and ^a : (static member get_Zero : -> ^a) and
^a : (static member ( / ) : ^a * ^a -> ^a)
(that's why I don't like to write this in the ad;))
As you can see, there is support for generic numeric code, but this is not often discussed (F # has some type of type in which they are built in - here's an example, others like comparable
and so on).
Tomas wrote a good article about this: Writing Generic Numeric Code
PS you don't need it either ^a
- but I like writing the signature - and even if you can do it:
let inline (/!) a b =
if b = LanguagePrimitives.GenericZero
then LanguagePrimitives.GenericZero
else a / b
val inline ( /! ) :
a: ^a -> b: ^b -> ^c
when ( ^a or ^b) : (static member ( / ) : ^a * ^b -> ^c) and
^b : (static member get_Zero : -> ^b) and ^b : equality and
^c : (static member get_Zero : -> ^c)
it won't help you, as real division operators usually only have one type for both arguments - and as I said: I like to underscore types over argument names;)
fun fact
you can bypass the tag GenericZero
like this:
> let inline (/!) a b = if b = (b-b) then (b-b) else a/b;;
val inline ( /! ) :
a: ^a -> b: ^b -> ^b
when ( ^a or ^b) : (static member ( / ) : ^a * ^b -> ^b) and
^b : (static member ( - ) : ^b * ^b -> ^b) and ^b : equality
(To be on the safe side: you might run into problems with certain types / numbers here;))
source to share