uso usando una tipo ser requiere referencia programacion poo parametros parametrizada objeto genericos generico generica debe cuando crear clase argumentos generics f# overloading type-inference typeclass

generics - usando - Funciones con tipos de parámetros genéricos



programacion generica (5)

Aquí hay otra forma de usar las comprobaciones del tipo de tiempo de ejecución ...

let sqrt_int<''a> (x:''a) : ''a = // '' match box x with | :? int as i -> downcast (i |> float |> sqrt |> int |> box) | :? int64 as i -> downcast (i |> float |> sqrt |> int64 |> box) | _ -> failwith "boo" let a = sqrt_int 9 let b = sqrt_int 100L let c = sqrt_int "foo" // boom

Estoy intentando descubrir cómo definir una función que funcione en múltiples tipos de parámetros (por ejemplo, int e int64). Según tengo entendido, la sobrecarga de funciones no es posible en F # (sin duda el compilador se queja). Tomemos por ejemplo la siguiente función.

let sqrt_int = function | n:int -> int (sqrt (float n)) | n:int64 -> int64 (sqrt (float n))

El compilador, por supuesto, se queja de que la sintaxis no es válida (parece que no se admiten las restricciones de tipo en la coincidencia de patrones), aunque creo que esto ilustra lo que me gustaría lograr: una función que opera en varios tipos de parámetros y devuelve un valor de tipo. Tengo la sensación de que esto es posible en F # usando una combinación de tipos genéricos / inferencia de tipo / coincidencia de patrones, pero la sintaxis me ha eludido. También he intentado usar el:? operador (pruebas de tipo dinámico) y cuando las cláusulas en el bloque de coincidencia de patrones, pero esto todavía produce errores de todo tipo.

Como soy bastante nuevo en el lenguaje, es posible que intente hacer algo imposible aquí, así que por favor avíseme si hay una solución alternativa.


Esto funciona:

type T = T with static member ($) (T, n:int ) = int (sqrt (float n)) static member ($) (T, n:int64) = int64 (sqrt (float n)) let inline sqrt_int (x:''t) :''t = T $ x

Utiliza restricciones estáticas y sobrecarga, lo que hace una búsqueda en tiempo de compilación sobre el tipo de argumento.

Las restricciones estáticas se generan automáticamente en presencia de un operador (operador $ en este caso) pero siempre se puede escribir a mano:

type T = T with static member Sqr (T, n:int ) = int (sqrt (float n)) static member Sqr (T, n:int64) = int64 (sqrt (float n)) let inline sqrt_int (x:''N) :''N = ((^T or ^N) : (static member Sqr: ^T * ^N -> _) T, x)

Más sobre esto here .


La sobrecarga suele ser el cúmulo de idiomas de tipo inferencial (al menos cuando, como F #, el sistema de tipo no es lo suficientemente potente como para contener clases de tipo). Hay varias opciones que tiene en F #:

  • Utilice la sobrecarga en métodos (miembros de un tipo), en cuyo caso la sobrecarga funciona de forma similar a otros lenguajes .Net (puede ad-hoc sobrecargar miembros, las llamadas provistas pueden distinguirse por el número / tipo de parámetros)
  • Use "en línea", "^" y restricciones de miembros estáticos para la sobrecarga ad-hoc en las funciones (esto es lo que la mayoría de los diversos operadores matemáticos que necesitan trabajar en int / float / etc .; la sintaxis aquí es rara, esto es poco utilizado, aparte de la biblioteca F #)
  • Simule clases de tipos pasando un parámetro adicional de diccionario de operaciones (esto es lo que INumeric hace en una de las bibliotecas F # PowerPack para generalizar varios algoritmos matemáticos para tipos arbitrarios definidos por el usuario)
  • Vuelva a la tipificación dinámica (pase un parámetro ''obj'', realice una prueba dinámica de tipo, ejecute una excepción en tiempo de ejecución para el tipo incorrecto)

Para su ejemplo particular, probablemente solo usaría la sobrecarga de métodos:

type MathOps = static member sqrt_int(x:int) = x |> float |> sqrt |> int static member sqrt_int(x:int64) = x |> float |> sqrt |> int64 let x = MathOps.sqrt_int 9 let y = MathOps.sqrt_int 100L


No quitar las respuestas correctas ya provistas, pero de hecho puede usar restricciones de tipo en la coincidencia de patrones. La sintaxis es:

| :? type ->

O si desea combinar el control de tipos y el casting:

| :? type as foo ->


Si, esto se puede hacer. Eche un vistazo a este hilo de HubFS .

En este caso, la solución sería:

let inline retype (x:''a) : ''b = (# "" x : ''b #) let inline sqrt_int (n:''a) = retype (sqrt (float n)) : ''a

Advertencia : no hay verificación de tipos en tiempo de compilación. Es decir, sqrt_int "blabla" compila bien, pero obtendrá FormatException en tiempo de ejecución.