F # assuming int when dealing with int64

After going through Project Euler , trying to find out F #, I came across what seems like a type inference problem when writing a solution for problem 3 .

Here is what I wrote:

let rec findLargestPrimeFactor pn = if n = 1 then p else if n % p = 0 then findLargestPrimeFactor p (n/p) else findLargestPrimeFactor (p+1) n let result = findLargestPrimeFactor 2 600851475143L 

However, the compiler gives me the following error:

  error FS0001: This expression was expected to have type int but here has type int64 

Since I expect the types used in findLargestPrimeFactor to be taken out of use, I was surprised to find that the compiler seems to assume that the parameter n is int, because in the case where only a function call with int64 is executed.

Can someone explain to me:

  • why the compiler seems to get confused in types
  • how to get around this limitation
+4
type-inference f #
Feb 21 '13 at 17:16
source share
1 answer

Types from findLargestPrimeFactor are no findLargestPrimeFactor in use. The F # compiler performs type inference on a top-down basis, so the types p and n (parameters findLargestPrimeFactor ) are inferred from their use in the function. By the time the compiler sees let result = ... , the parameter types have already been inferred as int .

The simplest solution is to use the L suffix for all of your constant values, so the types will be inferred as int64 :

 let rec findLargestPrimeFactor pn = if n = 1L then p else if n % p = 0L then findLargestPrimeFactor p (n/p) else findLargestPrimeFactor (p + 1L) n let result = findLargestPrimeFactor 2L 600851475143L 

If you want a better solution, you can use general and zero constants from the LanguagePrimitives module. This allows findLargestPrimeFactor be generic (-ish) so that it can be reused with different numeric types:

 open LanguagePrimitives let rec findLargestPrimeFactor pn = if n = GenericOne then p else if n % p = GenericZero then findLargestPrimeFactor p (n/p) else findLargestPrimeFactor (p + GenericOne) n (* You can use one of these, but not both at the same time -- now the types of the _arguments_ are used to infer the types of 'p' and 'n'. *) //let result = findLargestPrimeFactor 2L 600851475143L let result = findLargestPrimeFactor 2 Int32.MaxValue 

According to the @kvb suggestion, here you can write this function in general form:

 open LanguagePrimitives let inline findLargestPrimeFactor pn = let rec findLargestPrimeFactor pn = if n = GenericOne then p else if n % p = GenericZero then findLargestPrimeFactor p (n/p) else findLargestPrimeFactor (p + GenericOne) n findLargestPrimeFactor pn (* Now you can call the function with different argument types as long as the generic constraints are satisfied. *) let result = findLargestPrimeFactor 2L 600851475143L let result' = findLargestPrimeFactor 2 Int32.MaxValue 
+10
Feb 21 '13 at 17:41
source share



All Articles