Sto provando a scrivere una libreria di misurazioni delle prestazioni per Scala. La mia idea è di contrassegnare in modo trasparente le sezioni in modo da poter raccogliere i tempi di esecuzione. Sfortunatamente non ero in grado di piegare il compilatore alla mia volontà.Come si crea una funzione parziale con generici in scala?
Un esempio certamente forzato di quello che ho in mente:
// generate a timing function
val myTimer = mkTimer('myTimer)
// see how the timing function returns the right type depending on the
// type of the function it is passed to it
val act = actor {
loop {
receive {
case 'Int =>
val calc = myTimer { (1 to 100000).sum }
val result = calc + 10 // calc must be Int
self reply (result)
case 'String =>
val calc = myTimer { (1 to 100000).mkString }
val result = calc + " String" // calc must be String
self reply (result)
}
Ora, questo è il più lontano ho ottenuto:
trait Timing {
def time[T <: Any](name: Symbol)(op: => T) :T = {
val start = System.nanoTime
val result = op
val elapsed = System.nanoTime - start
println(name + ": " + elapsed)
result
}
def mkTimer[T <: Any](name: Symbol) : (() => T) =>() => T = {
type c =() => T
time(name)(_ : c)
}
}
Utilizzando la funzione time
lavora direttamente e il compilatore utilizza correttamente la restituire il tipo della funzione anonima per digitare la funzione "orario":
val bigString = time('timerBigString) {
(1 to 100000).mkString("-")
}
println (bigString)
grande come sembra, questo modello ha una serie di carenze:
- costringe l'utente a riutilizzare lo stesso simbolo a ogni invocazione
- rende più difficile fare cose più avanzate come predefiniti timer a livello di progetto
- non permette la libreria per inizializzare una volta una struttura di dati per 'timerBigString
Quindi qui si tratta mkTimer, che mi permettesse di applicare parzialmente la funzione di tempo e riutilizzarlo. Io uso mkTimer come questo:
val myTimer = mkTimer('aTimer)
val myString= myTimer {
(1 to 100000).mkString("-")
}
println (myString)
Ma ottengo un errore di compilazione:
error: type mismatch;
found : String
required:() => Nothing
(1 to 100000).mkString("-")
ottengo lo stesso errore se InLine l'accattivarsi:
val timerBigString = time('timerBigString) _
val bigString = timerBigString {
(1 to 100000).mkString("-")
}
println (bigString)
Questo funziona se lo faccio val timerBigString = time('timerBigString) (_: String)
, ma questo non è quello che voglio. Mi piacerebbe posticipare la digitazione della funzione parzialmente applicata fino all'applicazione.
Concludo che il compilatore sta decidendo il tipo di ritorno della funzione parziale quando lo creo per la prima volta, scegliendo "Nothing" perché non può fare una scelta più informata.
Quindi immagino che quello che sto cercando sia una sorta di late-binding della funzione parzialmente applicata. C'è un modo per fare questo? O forse c'è un percorso completamente diverso che potrei seguire?
Bene, grazie per aver letto fin qui
-teo
Spot on! Grazie. –