2013-04-19 3 views
7

Perché il valore fail genera un'eccezione? Il valore fine funziona. Se rimuovo inline o se converto 't in float allora funziona. messaggioL'operatore Inline plus in struct genera un'eccezione (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 

errore:

Eccezione non gestita: System.TypeInitializationException: L'inizializzatore di tipo 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 () --- Fine dell'analisi dello stack eccezione interna - - in Microsoft.FSharp.Core.LanguagePrimitives.AdditionDynamic [T1, T2, TResult] (T1 x, T2 y) a. $ Program.main @() in C: \ Users \ olsv \ Docume nts \ Visual Studio 2012 \ Projects \ Consol eApplication1 \ ConsoleApplication1 \ Program. fs: linea 14 Premere un tasto qualsiasi per continuare. . .

risposta

5

Questo appare come un bug nel compilatore - o mi manca qualcosa (si prega di segnalarlo al fsbugs a microsoft dot com). Per qualche motivo, il compilatore non riesce a incorporare la chiamata all'operatore + (sembra funzionare per - e / e per operatori personalizzati come +., ma non riesce per + e *).

Ciò significa che il compilatore genera in realtà qualcosa di simile:

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

Il metodo utilizza alcuni AdditionDynamic tabella interna per trovare un'implementazione di + per i due tipi in fase di esecuzione. Sebbene tu possa registrare il tuo tipo lì, non sarebbe davvero utile, perché l'invocazione sarebbe lenta.

Io in realtà non ho alcuna soluzione bello per questo - se è necessario l'operatore solo per alcuni tipi di base numerici (float, int, ecc), allora l'opzione più semplice potrebbe essere quella di evitare solo utilizzando inline qui e definire (un sovraccarico) dell'operatore per i tipi specifici:

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

Si può anche provare il trucco con operatore globale e un tipo di supporto che implementa i vari sovraccarichi, ma non sono sicuro se questo sta andando ad aiutare: si veda, ad esempio, , this past question.