2013-04-19 14 views
7

Dlaczego wartość fail rzuca wyjątek? fine wartość działa. Jeśli usuniemy inline lub skonwertuję 't na float, to działa. KomunikatOperator Inline plus w struct zgłasza wyjątek (F #)

[<Struct>] 
type Test<'t> = 
    val x: 't 
    val y: 't 
    new (x,y) = { x = x; y = y } 

    static member inline (+) ((x,y), a: _ Test) = 0 
    static member inline (-) ((x,y), a: _ Test) = 0 

let a = 1.,2. 
let b = Test(1.,2.) 
let fine = a - b 
let fail = a + b 

błąd:

Nieobsłużone Wyjątek System.TypeInitializationException: typ inicjatora FO R AdditionDynamicImplTable 3' threw an exception. ---> System.NotSupportedExcep tion: Dynamic invocation of op_Addition involving coercions is not supported. at [email protected][a,b,c](Type aty, Type bt y, Unit unitVar0) at Microsoft.FSharp.Core.LanguagePrimitives.AdditionDynamicImplTable 3..cctor () --- Koniec wewnętrznej śledzenia wyjątku stosu - - w witrynie Microsoft.FSharp.Core.LanguagePrimitives.AdditionDynamic [T1, T2, TRESult] (T1 x, T2 y) at. $ Program.main @() w C: \ Users \ olsv \ Docume . Visual Studio 2012 \ Projects \ Consol eApplication1 \ ConsoleApplication1 \ Program. fs: linia 14 Naciśnij dowolny klawisz, aby kontynuować. . .

Odpowiedz

5

To wygląda na błąd w kompilator - albo ja czegoś brakuje (prosimy zgłosić go na fsbugs w microsoft kropką com). Z jakiegoś powodu kompilator nie może zainicjować połączenia z operatorem + (wydaje się, że działa on pod - i / i dla niestandardowych operatorów, takich jak +., ale nie powiedzie się dla + i *).

Oznacza to, że kompilator generuje faktycznie coś takiego:

// Inlined - returns zero directly 
fine = 0; 

// Failed to inline - calls a version which used dynamic lookup 
fail = LanguagePrimitives.AdditionDynamic 
     <Tuple<double, double>, Test.Test<double>, double>(a, b); 

AdditionDynamic Metoda wykorzystuje jakąś wewnętrzną tablicę znaleźć implementację + dla dwóch typów w czasie wykonywania. Chociaż można tam zarejestrować swój typ, nie byłoby to użyteczne, ponieważ wywołanie byłoby powolne.

naprawdę nie mają żadnego ładne obejście tego - jeśli trzeba operatorowi tylko dla niektórych podstawowych typów numerycznych (float, int, etc.), najprostszym rozwiązaniem może być po prostu unikać inline tutaj i zdefiniować (an przeciążony) operator dla poszczególnych typów:

static member (+) ((x:float,y:float), a: float Test) = x + y + a.x + a.y 

Możesz także spróbować sprawę z globalnego operatora i rodzaju pomocnika, który implementuje różne przeciążenia, ale nie jestem pewien, czy to pomoże: patrz, na przykład , this past question.