2010-08-25 14 views
78

So che questa domanda è venuta fuori molte volte in modi diversi. Ma non è ancora chiaro per me. C'è un modo per ottenere quanto segue.scala tuple disimballaggio

def foo(a:Int, b:Int) = {} 

foo(a,b) //right way to invoke foo 

foo(getParams) // is there a way to get this working without explicitly unpacking the tuple?? 

def getParams = { 
    //Some calculations 
    (a,b) //where a & b are Int 
} 
+11

Cosa succede se foo sembra essere il costruttore di qualche classe? – scout

+0

Possibile duplicato di [Come applicare una funzione a una tupla?] (Http://stackoverflow.com/questions/1987820/how-to-apply-a-function-to-a-uple) – Suma

risposta

95

È una procedura in due fasi. Prima gira foo in una funzione, quindi chiama tupla su di essa per renderla una funzione di una tupla.

(foo _).tupled(getParams) 
+3

Non sarebbe più pulito se Scala avesse appena pensato ad argomenti come Tuples per cominciare? –

+11

Sì, sarebbe molto più pulito se Scala unificasse la sua gestione di tuple e liste di argomenti. Da quello che ho sentito, ci sono molti casi limite non ovvi che avrebbero bisogno di un'attenta gestione per farlo accadere. Per quanto ne so, l'unificazione delle tuple e degli elenchi di argomenti non è attualmente sulla roadmap di Scala. –

+2

Solo per aggiungere, se foo è il metodo factory dell'oggetto companion, si potrebbe usare (Foo.apply _). Tupled (getParams) – RAbraham

17

Function.tupled(foo _)(getParams) o quello suggerito da Dave.

EDIT:

Per rispondere al tuo commento:

E se foo sembra essere il costruttore di una classe?

In questo caso, questo trucco non funzionerà.

È possibile scrivere un metodo factory nell'oggetto companion della classe e quindi ottenere la versione tupla del suo metodo apply utilizzando una delle tecniche di cui sopra.

scala> class Person(firstName: String, lastName: String) { 
    | override def toString = firstName + " " + lastName 
    | } 
defined class Person 

scala> object Person { 
    | def apply(firstName: String, lastName: String) = new Person(firstName, lastName) 
    | } 
defined module Person 

scala> (Person.apply _).tupled(("Rahul", "G")) 
res17: Person = Rahul G 

Con case class es si ottiene un oggetto associato con un metodo apply gratuitamente, e quindi questa tecnica è più comodo da usare con case class es.

scala> case class Person(firstName: String, lastName: String) 
defined class Person 

scala> Person.tupled(("Rahul", "G")) 
res18: Person = Person(Rahul,G) 

So che è un sacco di duplicazione del codice ma ahimè ... non abbiamo macro (ancora)! ;)

+3

Nell'ultimo esempio qui, si potrebbe radere un po '... Oggetti Companion per caso le classi estendono sempre il tratto FunctionN appropriato. Quindi l'ultima riga potrebbe essere '' Person.tupled (("Rahul", "G")) '' È utile farlo anche in oggetti compatti scritti a mano. –

+0

@ David: Modificato, grazie. :-) – missingfaktor

48

@ dave-griffith è morto.

Si può anche chiamare:

Function.tupled(foo _) 

Se si vuole vagare in "modo più informazioni di quante ho chiesto" il territorio, ci sono anche metodi incorporati in funzioni parzialmente applicate (e su Function) per accattivarsi. Alcuni esempi di ingresso/uscita:

scala> def foo(x: Int, y: Double) = x * y 
foo: (x: Int,y: Double)Double 

scala> foo _ 
res0: (Int, Double) => Double = <function2> 

scala> foo _ tupled 
res1: ((Int, Double)) => Double = <function1> 

scala> foo _ curried 
res2: (Int) => (Double) => Double = <function1> 

scala> Function.tupled(foo _) 
res3: ((Int, Double)) => Double = <function1> 

// Function.curried is deprecated 
scala> Function.curried(foo _) 
warning: there were deprecation warnings; re-run with -deprecation for details 
res6: (Int) => (Double) => Double = <function1> 

in cui la versione al curry viene richiamato con più liste di argomenti:

scala> val c = foo _ curried 
c: (Int) => (Double) => Double = <function1> 

scala> c(5) 
res13: (Double) => Double = <function1> 

scala> c(5)(10) 
res14: Double = 50.0 

Infine, è anche possibile uncurry/untuple, se necessario. Function ha comandi incorporati per questo:

scala> val f = foo _ tupled 
f: ((Int, Double)) => Double = <function1> 

scala> val c = foo _ curried 
c: (Int) => (Double) => Double = <function1> 

scala> Function.uncurried(c) 
res9: (Int, Double) => Double = <function2> 

scala> Function.untupled(f) 
res12: (Int, Double) => Double = <function2> 

1

Ora, è possibile implementare foo e renderlo prendere un param della classe Tuple2 in questo modo.

def foo(t: Tuple2[Int, Int]) = { 
    println("Hello " + t._1 + t._2) 
    "Makes no sense but ok!" 
} 

def getParams = { 
    //Some calculations 
    val a = 1; 
    val b = 2; 
    (a, b) //where a & b are Int 
} 

// So you can do this! 
foo(getParams) 
// With that said, you can also do this! 
foo(1, 3) 
2

apprezzo alcune delle altre risposte che erano più vicino a quello che hai chiesto, ma ho trovato più facile per un progetto in corso per aggiungere un'altra funzione che converte i parametri di tuple nei parametri di divisione:

def originalFunc(a: A, b: B): C = ... 
def wrapperFunc(ab: (A, B)): C = (originalFunc _).tupled(ab)