generics math f# inline

generics - ¿F#tiene soporte aritmético genérico?



math inline (4)

¿F # tiene el mismo problema que C # en el que no puede usar directamente operadores aritméticos con tipos T genéricos?

¿Se puede escribir una función Suma genérica que devuelva la suma de cualquier valor que admita la adición aritmética?


Como mencionó Brian, hay una cierta compatibilidad incorporada para la aritmética genérica y puede usar ''restricciones estáticas'' que le permiten definir algunas funciones genéricas usted mismo (aunque esto es un poco limitado).

Además de esto, también puede usar "asociaciones numéricas" dinámicas, que son un poco más lentas cuando se usan en una función, pero se pueden usar muy bien, por ejemplo, para definir su propio vector o tipo de matriz. Aquí hay un ejemplo:

#r "FSharp.PowerPack.dll" open Microsoft.FSharp.Math let twoTimesLarger (n:''a) (m:''a) = let ops = GlobalAssociations.GetNumericAssociation<''a>() let sel = if ops.Compare(n, m) > 0 then n else m ops.Multiply(sel, ops.Add(ops.One, ops.One))

Primero necesitamos hacer referencia a la biblioteca F # PowerPack que contiene la funcionalidad. Luego definimos una función genérica con una firma ''a -> ''a -> ''a . La primera línea obtiene dinámicamente operaciones numéricas para trabajar con el tipo ''a (esencialmente usa una tabla de búsqueda con el tipo como clave). Luego, puede usar métodos del objeto de operaciones numéricas para realizar cosas como la multiplicación, la suma ( Multiply , Add ) y muchos otros. La función funciona con cualquier número:

twoTimesLarger 3 4 twoTimesLarger 2.3 2.4 twoTimesLarger "a" "b" // Throws an exception!

Cuando define su propio tipo numérico, puede definir sus operaciones numéricas y registrarlas utilizando GlobalAssociations.RegisterNumericAssociation . Creo que esto también significa que podrá utilizar la Matrix<YourType> F # Matrix<YourType> y Vector<YourType> después de registrar las operaciones.


El mejor mecanismo que conozco para realizar aritmética genérica son las clases de tipo que, lamentablemente, ni C #, F #, ni el tiempo de ejecución .Net admiten en general. Sin embargo, puedes simularlos tú mismo a mano, como se menciona en esta publicación del blog:

Clases tipo son la salsa secreta

Esa técnica debería funcionar en C # 2.0 o posterior (utilizando delegados anónimos / lambdas).

A menudo las personas recurren a las interfaces, pero se encuentran con un par de problemas

  1. No puede declarar que el tipo existente implementa una interfaz, por lo que no puede definir una instancia de esa interfaz para tipos integrados como int.
  2. Las interfaces no pueden restringir el tipo de otros argumentos a los métodos.

Una interfaz declara que, para todas las implementaciones, todos los métodos en esa interfaz toman el mismo tipo implícito de parámetro ''this''. Si Foo implementa alguna interfaz, obviamente, el parámetro ''esto'' debe ser del tipo Foo para esa implementación. Pero no hay forma de exigir que otros parámetros de método también sean del tipo Foo.

Las clases de tipos le permiten (entre otras cosas) realizar este tipo de restricción en todos los parámetros del método, no solo en el primer parámetro.

Como se mencionó en el artículo citado anteriormente, puede simular clases de tipos pasando tablas de funciones como argumentos explícitos.

(La wiki de la comunidad: publicaría un ejemplo de ese artículo traducido a C # aquí, pero se quedó sin tiempo con una explicación larga)


F # tiene un apoyo limitado para esto. Una buena solución general probablemente involucra clases de tipo, que no son compatibles con el CLR en general, o F # en particular.

F # ha sobrecargado a los operadores aritméticos que utilizan las "restricciones de miembro estático" y las funciones "en línea". Esta es la magia que permite, por ejemplo, que el operador + trabaje tanto en int s como en float s. Puede escribir funciones en inline cuyas implementaciones se basen en los operadores matemáticos incorporados y hacer algún progreso, pero en general no es trivial. Puede revisar, por ejemplo, el código fuente a Array.sum (en array.fs en FSharp.Core) en la distribución de fuente F # que viene junto con el CTP para tener una idea.

Vea también la parte de ''restricciones de miembros estáticos'' y ''simular clases de tipos'' de esta respuesta:

Funciones con tipos de parámetros genéricos.

así como varios bits de la biblioteca como

http://msdn.microsoft.com/en-us/library/ee370581(VS.100).aspx

http://msdn.microsoft.com/en-us/library/ee340262(VS.100).aspx


Podrías hacer algo como esto.

let inline sum<''a when ''a : (static member (+) : ''a -> ''a -> ''a)> a b = a + b let result = sum<int> 3 4

Sin embargo, si intento let result = sum 3 4 recibo el error "type ambiguity inherent in the use of the operator ''( + )''"