Спасибо за этот вопрос - это действительно хороший отчет об ошибке с простым воспроизведением, и я не мог в это поверить, но вы совершенно правы. Плюс работает, а минус нет.
Проблема заключается в том, что sub
и add
скомпилированы как универсальные методы, а версия LINQ вызывает эти универсальные методы. Встраивание выполняется после сохранения цитат, поэтому код в кавычках содержит вызов метода sub
. Это не проблема в обычном коде F#, поскольку функции являются встроенными, а операторы разрешаются в + или - для некоторых числовых типов.
Однако в универсальной версии используется динамический поиск. Если вы посмотрите на prim-types.fs:3530
, вы увидите:
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
AdditionDynamic
— это то, что вызывается из универсального метода. Он выполняет динамический поиск, который будет медленнее, но будет работать. Интересно, что для оператора минус библиотека F# не включает динамическую реализацию:
[<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
Я понятия не имею, почему это так - я не думаю, что есть какая-то техническая причина, но это объясняет, почему вы получаете поведение, о котором сообщили. Если вы посмотрите на скомпилированный код с помощью ILSpy, вы увидите, что метод add
что-то делает, а метод sub
просто генерирует исключение (так вот откуда возникает исключение).
Что касается обходного пути, вам нужно написать код таким образом, чтобы он не использовал универсальный оператор минус. Вероятно, лучший вариант — избегать функций inline
(используя либо sub_int
, либо sub_float
) или писать собственную динамическую реализацию sub
(что, вероятно, можно сделать довольно эффективно с помощью DLR (см.
person
Tomas Petricek
schedule
19.09.2011
NoDynamicInvocation
-
скрыт во время компиляции, и его нельзя обойти. . - person Stephen Swensen   schedule 19.09.2011-
): fsharppowerpack.codeplex.com/workitem/5882, но теперь я считаю, что об этом нужно сообщить непосредственно команде компилятора. - person Stephen Swensen   schedule 19.09.2011