f# type-inference

F#suponiendo int cuando en realidad se trata de int64



type-inference (1)

Al pasar por el Proyecto Euler tratando de aprender F #, me encontré con lo que parece ser un problema de inferencia de tipo al escribir una solución para el problema 3 .

Esto es lo que escribí:

let rec findLargestPrimeFactor p n = 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

Sin embargo, el compilador me da el siguiente error:

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

Como espero que los tipos utilizados en findLargestPrimeFactor del uso, me sorprende descubrir que el compilador parece suponer que el parámetro n es una int, ya que en la única llamada a la función se hace con un int64.

¿Podría alguien explicarme:

  1. por qué el compilador parece estar confundido acerca de los tipos
  2. cómo evitar esta limitación

Los tipos en findLargestPrimeFactor se deducen del uso. El compilador F # realiza la inferencia de tipo de arriba a abajo, de modo que los tipos de p y n (los parámetros de findLargestPrimeFactor ) se deducen de su uso en la función. Para cuando el compilador ve el let result = ... , los tipos de parámetros ya se han inferido como int .

La solución más fácil es usar el sufijo L en todos sus valores constantes, por lo que los tipos se int64 como int64 :

let rec findLargestPrimeFactor p n = 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

Si desea una solución más elegante, puede usar las constantes genéricas y cero del módulo LanguagePrimitives . Esto permite que findLargestPrimeFactor sea ​​genérico (-ish) para que pueda reutilizarse más fácilmente con diferentes tipos numéricos:

open LanguagePrimitives let rec findLargestPrimeFactor p n = 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

La sugerencia de Per @ kvb, así es como puedes escribir esta función genéricamente:

open LanguagePrimitives let inline findLargestPrimeFactor p n = let rec findLargestPrimeFactor p n = if n = GenericOne then p else if n % p = GenericZero then findLargestPrimeFactor p (n/p) else findLargestPrimeFactor (p + GenericOne) n findLargestPrimeFactor p n (* 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