Gracias por esta pregunta - que es un muy buen informe de error con un simple repro y no podía creer esto, pero tienes toda la razón. Más funciona, pero menos no.
El problema es quesub
y add
se compilan como los métodos genéricos y la versión de LINQ invoca estos métodos genéricos. La alineación se realiza después de que las citas se almacenen, por lo que el código entre comillas contiene una llamada al método sub
. Esto no es un problema en el código F # normal, porque las funciones están en línea y los operadores están resueltos a + o - en algunos tipos numéricos.
Sin embargo, la versión genérica utiliza una búsqueda dinámica. Si nos fijamos en prim-types.fs:3530
, verá:
let inline (+) (x: ^T) (y: ^U) : ^V =
AdditionDynamic<(^T),(^U),(^V)> x y
when ^T : int32 and ^U : int32 = (# "add" x y : int32 #)
when ^T : float and ^U : float = (# "add" x y : float #)
// ... lots of other cases
El AdditionDynamic
es lo que se llama desde el método genérico. Hace la búsqueda dinámica, que será más lenta, pero funcionará. Curiosamente, para el operador menos, la biblioteca # F no incluir la implementación dinámica:
[<NoDynamicInvocation>]
let inline (-) (x: ^T) (y: ^U) : ^V =
((^T or ^U): (static member (-) : ^T * ^U -> ^V) (x,y))
when ^T : int32 and ^U : int32 = (# "sub" x y : int32 #)
when ^T : float and ^U : float = (# "sub" x y : float #)
// ... lots of other cases
no tengo ni idea de por qué este es el caso - no creo que haya ninguna razón técnica, pero explica por qué obtener el comportamiento que informaste Si observa el código compilado utilizando ILSpy, verá que el método add
hace algo y el método sub
acaba de lanzar (por lo que aquí es de donde proviene la excepción).
En cuanto a una solución, debe escribir el código de forma que no utilice el operador genérico negativo. Probablemente, la mejor opción es evitar inline
funciones (ya sea mediante el uso de sub_int
o sub_float
) o escribiendo su propia implementación dinámica de sub
(que se puede hacer probablemente muy eficiente usando DLR (ver this post).
Trate de no usar el PowerPack de métodos de evaluación. Si realmente tiene que hacerlo, hay otras maneras de evaluar citas. Por ejemplo, Unquote de Stephen Swensen (http://code.google.com/p/unquote/). –
@Ramon, mientras aprecio el aprobación, y estoy de acuerdo en que el evaluador de Unquote puede ser una mejor opción en muchos escenarios (evaluación no compilada más rápida, admite más patrones de cotización, admite Silverlight 4, probablemente menos errores por ser más simple), necesito apuntar que este problema es más profundo que cualquier motor de evaluación puede manejar y así se puede ver en el evaluador de Unquote también: la llamada problemática al operador 'NoDynamicInvocation'' -' está enterrada en el momento de la compilación y no se puede evitar. –
Presenté un error con el proyecto PowerPack por básicamente el mismo problema hace un tiempo (aunque no entendí que '-' era el problema en ese momento): http: //fsharppowerpack.codeplex.com/workitem/5882, pero ahora creo que esto es algo que debe informarse directamente al equipo del compilador. –