2014-11-28 21 views
5

Sono nuovo di F # e sono stato sorpreso di scoprire che il tipo di f x y = x + y è in realtà int -> int -> int. Appearently, questo è dovuto ad alcuni compromessi in termini di prestazioni.Perché il tipo di argomento degli operatori aritmetici è impostato su int?

Ma perché è effettivamente necessario? Perché non solo dedurre il tipo di essere 'a -> 'a -> 'a o qualcosa di simile? Sembra funzionare per il confronto: il tipo di g x y = x < y è x:'a -> y:'a -> bool when 'a : comparison. Perché non anche per gli operatori aritmetici?

Non è possibile che il compilatore deduca staticamente i tipi primitivi specifici dai siti di chiamata e specializzi la funzione generica da lì, ricadendo in qualche dispatch dinamico se questo non riesce?

Questo potrebbe essere molto ovvio, ma non ho trovato alcuna buona risorsa in questo. Qual è il ragionamento dietro questo comportamento?

risposta

7

Sì, per quegli operatori int è il tipo predefinito desunto a meno che non si specifichi uno diverso o venga dedotto dall'utilizzo. Se si desidera definire loro per tutti i tipi si deve fare la funzione inline:

let inline f x y = x + y 

a meno di notare che la firma è:

x: ^a -> y: ^b -> ^c 
    when (^a or ^b) : (static member (+) : ^a * ^b -> ^c) 

Questo perché in .NET non è possibile utilizzare member constraints ma F # li risolve in fase di compilazione. Ecco perché vedi quei 'tipi di cappello' e il vincolo che quei tipi dovrebbero avere un membro statico (+) definito.

Si noti inoltre che le variabili di tipo non sono a -> a -> a come suggerito, poiché nel framework .NET non tutte le operazioni di aggiunta rispettano tale firma. Le cose sono diverse in altri ambienti come Haskell, c'è l'aggiunta è strettamente a -> a -> a ma in .NET è possibile aggiungere per esempio un periodo di un DateTime:

System.DateTime(2000,1,1) + new System.TimeSpan(1, 2, 0, 30, 0) 

e il risultato è un DateTime, ecco la firma è: a -> b -> a

confronto è una storia diversa da quella effettivamente vincolo esistente a livello NET in modo che possa essere compilato e codificato nel iL mentre vincoli utente devono essere risolti in fase di compilazione, questo che la funzione deve essere contrassegnato come linea.

Penso che abbiate interpretato erroneamente la spiegazione nella domanda collegata: questo non è dovuto a un compromesso in termini di prestazioni, la vera ragione è una limitazione del sistema di tipo .NET. Il fatto che una funzione inline venga eseguita più velocemente nella maggior parte dei casi (poiché è delineata dal compilatore) è un effetto secondario.

+0

Grazie per questa risposta rapida ed eccellente. "in .NET non è possibile utilizzare i vincoli dei membri" <- questo è quello che non avevo realizzato. Non so perché, ma in qualche modo ho pensato che fosse possibile. Probabilmente dovrei RTFM prima di fare altre domande;) – user4235730

Problemi correlati