Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# - multiply int by float

Probably a silly question, but I just got started with F# and I've got a little problem.

Say I have a function like this:

let multiplyByTwo x = x * 2

When I call this like this:

let result = multiplyByTwo 5

Everything is alright, the result is 10.

When I call it like this:

let result = multiplyByTwo 2.5

I expect to get 5 or 5.0 as a result. The actual result however is this:

let result = multiplyByTwo 2.5;;
---------------------------------^^^

stdin(4,28): error FS0001: This expression was expected to have type

int     

but here has type

float

Because I want this function to be somewhat generic (i.e. accept both floating point numbers and integers), I don't like this. My question of course: how does one solve this?

like image 938
Leon Cullens Avatar asked May 30 '12 21:05

Leon Cullens


2 Answers

When you write a numeric literal in F# (such as 2 or 3.14), the compiler treats that as a value of a specific type and so code that uses numeric literals will not be polymorphic. You can either convert input to a single type and work with that type (like float in desco's answer) or use more advanced features of F#...

Certain numeric operations can be written in a polymorphic way, if you mark the code as inline (this way, the compiler can represent additional constraints and statically resolve them) and if you only use polymorphic primitives (with additional static constraints).

Standard operators are polymorpic in inline functions and the F# library provides a way to get polymorphic value representing 1 and 0 (though not 2), but that's enough to write the function you wanted:

let inline twoTimes n = 
  let one = LanguagePrimitives.GenericOne
  n * (one + one)

twoTimes 2
twoTimes 2.0

If you want to make this nicer, you can define a numeric literal (see Daniel's answer to earlier StackOverflow question) and then you can actually write just:

let inline twoTimes n = n * 2G

The special numeric literal 2G is translated to a call to a function of NumericLiteralG which sums specified number of generic 1 values using the technique I used above (so it won't be efficient for large numbers!) For more information, you see also my recent article on writing generic numeric code in F#.

like image 153
Tomas Petricek Avatar answered Nov 20 '22 07:11

Tomas Petricek


let inline mulBy2 x = (float x) * 2.0

let a = mulBy2 3 // 6.0 : float
let b = mulBy2 2.5 // 5.0 : float
let c = mulBy2 "4" // 8.0 : float
like image 12
desco Avatar answered Nov 20 '22 06:11

desco