2010-08-25 13 views
78

Sé que esta pregunta ha surgido muchas veces de diferentes maneras. Pero todavía no está claro para mí. ¿Hay alguna manera de lograr lo siguiente?scala tuple desempaquetado

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

¿Qué pasa si foo resulta ser el constructor de alguna clase? – scout

+0

Posible duplicado de [Cómo aplicar una función a una tupla?] (Http://stackoverflow.com/questions/1987820/how-to-apply-a-function-to-a-tuple) – Suma

Respuesta

95

Es un procedimiento de dos pasos. Primero convierte foo en una función, luego llama a tupled para que sea una función de una tupla.

(foo _).tupled(getParams) 
+3

¿No sería más limpio? si Scala solo pensó en argumentos como Tuples para empezar? –

+11

Sí, sería mucho más claro si Scala unificara su manejo de tuplas y listas de argumentos. Por lo que he escuchado, hay muchos casos extremos no obvios que necesitarían un manejo cuidadoso para que eso suceda. Por lo que yo sé, la unificación de tuplas y listas de argumentos no está en la hoja de ruta de Scala en este momento. –

+2

Solo para agregar, si foo es el método de fábrica del objeto complementario, se podría usar (Foo.apply _). Tupled (getParams) – RAbraham

17

Function.tupled(foo _)(getParams) o el sugerido por Dave.

EDIT:

Para responder a su comentario:

¿Qué pasa si foo pasa a ser el constructor de de alguna clase?

En ese caso, este truco no funcionará.

Puede escribir un método de fábrica en el objeto complementario de su clase y luego obtener la versión tuplada de su método apply usando una de las técnicas antes mencionadas.

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 usted consigue un objeto acompañante con un método apply de forma gratuita, y por lo tanto esta técnica es más cómodo de usar 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) 

Sé que es mucha duplicación de código pero lamentablemente ... ¡todavía no tenemos macros! ;)

+3

En el último ejemplo aquí, podría afeitarse un poco ... Objetos complementarios para el caso las clases siempre extienden el rasgo de FunctionN apropiado. Entonces, la última línea podría ser '' Person.tupled (("Rahul", "G")) '' También es útil para hacer esto en objetos complementarios escritos a mano. –

+0

@David: Editado, gracias. :-) – missingfaktor

48

@ dave-griffith está muerto.

También puede llamar a:

Function.tupled(foo _) 

Si quieres pasear en el "camino más información que pedí" territorio, también hay métodos incorporados en funciones aplicadas parcialmente (y en Function) para ganarse. Unos pocos ejemplos de entrada/salida:

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> 

caracterizado porque la versión de curry se invoca con múltiples listas de argumentos:

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 

Por último, también se puede uncurry/untuple si es necesario. Function tiene órdenes internas para esto:

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

Ahora, se puede implementar foo y hacerlo tomar un parámetro de la clase Tuple2 como tal.

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

aprecio algunas de las otras respuestas que estaban más cerca de lo que pidieron, pero me pareció más fácil para un proyecto actual para agregar otra función que convierte los parámetros de tupla en los parámetros intermedios:

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