2010-04-11 12 views
7

Qual è il problema con il seguente metodo?Utilizzo delle funzioni di valutazione lazy in varargs

def someMethod(funcs: => Option[String]*) = { 
... 
} 
+0

Il nome del parametro formale, 'funcs', è altamente sospetto. I parametri By-name, se implementati con un thunk, non sono funzioni apertamente. –

+0

Né sono quelli che vengono comunemente chiamati argomenti calcolati pigramente. Ad esempio, se si utilizza il valore più volte, l'espressione fornita come parametro effettivo viene valutata più volte. Ciò ha conseguenze sulle prestazioni e se quell'espressione ha effetti collaterali, si verificheranno anche moltiplica. –

+0

Questa potrebbe essere una soluzione: http://stackoverflow.com/a/34373967/2825964 –

risposta

5

Che in realtà "lavora" sotto 2.7.7 se si aggiunge parentesi:

scala> def someMethod(funcs: => (Option[String]*)) = funcs 
someMethod: (=> Option[String]*)Option[String]* 

tranne che in realtà non funziona in fase di esecuzione:

scala> someMethod(Some("Fish"),None) 
    scala.MatchError: Some(Fish) 
at scala.runtime.ScalaRunTime$.boxArray(ScalaRunTime.scala:136) 
at .someMethod(<console>:4) 
at .<init>(<console>:6) 
at .<clinit>(<console>) ... 

In 2.8 si rifiuta di consentire all'utente di specificare X * come l'uscita di ogni funzione o con-nome del parametro, anche se è possibile specificare come un ingresso (questo è r21230, post-Beta 1):

scala> var f: (Option[Int]*) => Int = _ 
f: (Option[Int]*) => Int = null 

scala> var f: (Option[Int]*) => (Option[Int]*) = _ 
<console>:1: error: no * parameter type allowed here 
     var f: (Option[Int]*) => (Option[Int]*) = _ 

Ma se si tenta di convertire da un metodo, funziona:

scala> def m(oi: Option[Int]*) = oi 
m: (oi: Option[Int]*)Option[Int]* 

scala> var f = (m _) 
f: (Option[Int]*) => Option[Int]* = <function1> 

scala> f(Some(1),None) 
res0: Option[Int]* = WrappedArray(Some(1), None) 

quindi non è del tutto coerente.

In ogni caso, si può eventualmente ottenere quello che vuoi, passando in un array e poi l'invio di tale matrice a qualcosa che richiede argomenti ripetuti:

scala> def aMethod(os: Option[String]*) { os.foreach(println) } 
aMethod: (os: Option[String]*)Unit 

scala> def someMethod(funcs: => Array[Option[String]]) { aMethod(funcs:_*) } 
someMethod: (funcs: => Array[Option[String]])Unit 

scala> someMethod(Array(Some("Hello"),Some("there"),None)) 
Some(Hello) 
Some(there) 
None 

Se si vuole veramente (facilmente) passare un mucchio di argomenti calcolati pigramente, quindi avete bisogno di un po 'di infrastruttura che per quanto ne so non esiste nella libreria (questo è il codice per 2.8, vista come ispirazione per una strategia simile in 2.7):

class Lazy[+T](t:() => T, lt: Lazy[T]) { 
    val params: List[() => T] = (if (lt eq null) Nil else t :: lt.params) 
    def ~[S >: T](s: => S) = new Lazy[S](s _,this) 
} 
object Lz extends Lazy[Nothing](null,null) { 
    implicit def lazy2params[T : Manifest](lz: Lazy[T]) = lz.params.reverse.toArray 
} 

Ora puoi creare facilmente un gruppo di param Eters che sono ponderati:

scala> import Lz._ // To get implicit def 
import Lz._ 

scala> def lazyAdder(ff: Array[()=>Int]) = { 
    | println("I'm adding now!"); 
    | (0 /: ff){(n,f) => n+f()} 
    | } 
lazyAdder: (ff: Array[() => Int])Int 

scala> def yelp = { println("You evaluated me!"); 5 } 
yelp: Int 

scala> val a = 3 
a: Int = 3 

scala> var b = 7 
b: Int = 7 

scala> lazyAdder(Lz ~ yelp ~ (a+b)) 
I'm adding now! 
You evaluated me! 
res0: Int = 15 

scala> val plist = Lz ~ yelp ~ (a+b) 
plist: Lazy[Int] = [email protected] 

scala> b = 1 
b: Int = 1 

scala> lazyAdder(plist) 
I'm adding now! 
You evaluated me! 
res1: Int = 9 
3

Evidentemente gli argomenti ripetuti non sono disponibili per i parametri di nome.

+0

Ma, solo per i calci, prova questo: 'def f (oi: Option [Int] *) = oi' nella REPL. Interessante, eh? –

+0

@Rex_Kerr: credo. A che cosa ti riferisci? –

+1

È possibile restituire Option [Int] * da un metodo ed è possibile utilizzare (f _) per renderlo una funzione. Ma prova a trovare la sintassi che ti permetta di rappresentare il tipo. Quindi non è chiaro per me se gli argomenti ripetuti non sono disponibili per i parametri di nome, o se la sintassi non ti consente di esprimere il tipo che vuoi (o entrambi). –

Problemi correlati