2010-01-21 34 views

Respuesta

23

Creo que la principal motivación para usar FSharpFunc<> en lugar de Func<> o cualquier otro delegado es que no puede crear una clase que heredaría de un tipo de delegado (al principio, esto suena razonable, pero en .NET, delegar es en realidad solo una clase especial, por lo que y ser en principio posible permitir esto). ¿Por qué es esto necesario?

Si escribe una función en F #, entonces (en un número relativamente pequeño, pero bastante importante) se trata con curry. Por ejemplo, int -> int -> int es en realidad un tipo de función int -> (int -> int) (currying significa que usted escribe una función usando solo funciones de un solo parámetro; si lo llama con el primer argumento, obtendrá una función como resultado y podrá invocar la función devuelta con el segundo argumento).

Si F # usó delegados, el tipo sería algo así como Func<int, Func<int, int>>. Como Brian mencionó, la invocación f x y se traduciría en dos invocaciones: f(x)(y). Sin embargo, este tipo de invocación es la más común (especificar solo un argumento se llama aplicación de función parcial). Por lo tanto, cuando F # compila una función como esta, se crea una clase heredada con un método de invocación optimizado, de modo que pueda ser invocada como f.Invoke(x, y):

class @some_F#[email protected] : Func<int, Func<int, int>> { 
    public int Invoke(int arg1, int arg2) { /* optimized call */ } 
} 

Por desgracia, no es posible crear dicha clase heredando desde estándar Func (porque es un delegado), por lo que F # tiene que declarar su propio tipo que se puede usar como clase base ...

+1

Gracias Tomas. Eso significa que no está destinado a ser llamado cuando no se está haciendo la interoperabilidad de C#, ¿lo entendí correctamente? – primfaktor

+1

Para la interoperabilidad, siempre expongo el código F # como un método que toma C# ordinario 'Func <...>' para hacer que la interoperación C# sea lo más suave posible. –

+0

Permítanme reformular: ¿Hay alguna razón para usarlo en el código F # normal (sin interposición)? – primfaktor

12

(creo que ahora llaman FSharpFunc en lugar de FastFunc.)

Está representado como un tipo con un único método abstracto (invocación), que creo que evita algunos de los gastos generales que se obtiene con verdaderos delegados. Y para múltiples parámetros al curry, que le permite llamar con todos los parámetros 'a la vez' en lugar de uno por uno (por ejemplo, de manera que f x y pueda recurrirse por el CLR como f(x,y) en lugar de f(x)(y).

¿Hay algo Si no recuerdo ahora, puede ver el código fuente en prim-types.fs en FSharp.Core en la distribución fuente que viene con la versión CTP.

+1

Por curiosidad, ¿se usa FSharpFunc de forma implícita cuando se escriben enlaces normales? – rysama

+1

Cada vez que necesite representar un _objeto_ con tipo X-> Y, creo que se representará como una instancia de FSharpFunc. Cuando define las funciones de let-bound, estas pueden representarse como los métodos normales de CLR, pero si está utilizando las funciones como valores (por ejemplo, pasándolo como un argumento a List.map o whatnot) entonces se representará a través de un FSharpFunc. – Brian

Cuestiones relacionadas