2013-04-19 7 views
7

Warum gibt der Wert fail eine Ausnahme aus? fine Wert funktioniert. Wenn ich inline entferne oder wenn ich 't in float umwandele, dann funktioniert es.Inline-Plus-Operator in Struktur löst eine Ausnahme aus (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 

Fehlermeldung:

Unbehandelte Ausnahme: System.TypeInitializationException: Die Typeninitialisierer 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 () --- Ende der Ausnahmestapelüberwachung - - bei Microsoft.FSharp.Core.LanguagePrimitives.AdditionDynamic [T1, T2, TResult] (T1 x, T2 y) um. $ Program.main @() in C: \ Benutzer \ olsv \ Docume nts \ Visual Studio 2012 \ Projekte \ Consol eApplication1 \ ConsoleApplication1 \ Programm. fs: line 14 Drücken Sie eine beliebige Taste, um fortzufahren. . .

Antwort

5

Dies sieht aus wie ein Bug im Compiler - oder ich bin etwas fehlt (bitte bei fsbugs bei microsoft dot berichten com). Aus irgendeinem Grund kann der Compiler den Anruf nicht an den Operator + anbinden (er scheint für - und / und für benutzerdefinierte Operatoren wie +. zu funktionieren, schlägt aber für + und * fehl).

Dies bedeutet, dass der Compiler generiert tatsächlich so etwas wie:

// 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); 

Die AdditionDynamic Methode verwendet eine interne Tabelle eine Implementierung von + für die beiden Typen zur Laufzeit zu finden. Obwohl Sie Ihren Typ dort registrieren könnten, wäre es nicht wirklich nützlich, weil der Aufruf langsam wäre.

Ich habe nicht wirklich eine schöne Abhilfe für dieses - wenn Sie den Operator nur für einige grundlegende numerische Typen benötigen (float, int, etc.), dann könnte die einfachste Option zu vermeiden, nur inline hier verwendet und definieren (ein überlastete) Operator für die spezifischen Typen:

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

Sie können auch den Trick mit dem globalen Operator versuchen und einem Helfer-Typ, der die verschiedenen Überlastungen implementiert, aber ich bin nicht sicher, ob das helfen geht: siehe zum Beispiel , this past question.

Verwandte Themen