descompactação de tupla scala

91

Sei que essa pergunta surgiu muitas vezes de maneiras diferentes. Mas ainda não está claro para mim. Existe uma maneira de conseguir o seguinte.

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
}
batedor
fonte
11
E se foo for o construtor de alguma classe?
olheiro de
Possível duplicata de Como aplicar uma função a uma tupla?
Suma

Respostas:

107

É um procedimento de duas etapas. Primeiro transforme foo em uma função e, em seguida, chame tupled nele para torná-lo uma função de uma tupla.

(foo _).tupled(getParams)
Dave Griffith
fonte
3
Não seria mais limpo se Scala apenas pensasse em argumentos como Tuplas, para começar?
Henry Story
12
Sim, seria muito mais limpo se Scala unificasse seu manuseio de tuplas e listas de argumentos. Pelo que ouvi, há muitos casos extremos não óbvios que precisam de tratamento cuidadoso para que isso aconteça. Pelo que eu sei, a unificação de tuplas e listas de argumentos não está no roteiro do Scala no momento.
Dave Griffith
2
Apenas para adicionar, se foo é o método de fábrica do objeto companheiro, pode-se usar (Foo.apply _). Tupled (getParams)
RAbraham
55

@ dave-griffith está certo.

Você também pode ligar para:

Function.tupled(foo _)

Se você quiser entrar no território de "muito mais informações do que eu pedi", também existem métodos embutidos em funções parcialmente aplicadas (e Functionativadas) para currying. Alguns exemplos de entrada / saída:

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>

Onde a versão curried é invocada com múltiplas 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 fim, você também pode reduzir a pressa / desacelerar, se necessário. Functiontem builtins para isso:

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>

Brendan W. McAdams
fonte
20

Function.tupled(foo _)(getParams)ou aquele sugerido por Dave.

EDITAR:

Para responder ao seu comentário:

E se foo for o construtor de alguma classe?

Nesse caso, esse truque não funcionará.

Você pode escrever um método de fábrica no objeto companheiro de sua classe e, em seguida, obter a versão tuplada de seu applymétodo usando uma das técnicas acima 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

Com case classes, você obtém um objeto companheiro com um applymétodo gratuitamente e, portanto, essa técnica é mais conveniente para usar com case classes.

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

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

Eu sei que é muita duplicação de código, mas, infelizmente ... não temos macros (ainda)! ;)

faltando faktor
fonte
3
No último exemplo aqui, você poderia economizar um pouco ... Objetos companheiros para classes de caso sempre estendem o traço FunctionN apropriado. Portanto, a última linha pode ser Person.tupled(("Rahul", "G")) É útil fazer isso também em objetos companheiros escritos à mão.
David Winslow
3

Agradeço algumas das outras respostas que foram mais próximas do que você pediu, mas achei mais fácil para um projeto atual adicionar outra função que converte parâmetros de tupla em parâmetros de divisão:

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

Agora, você pode implementar foo e torná-lo um parâmetro da classe 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)
Rejinderi
fonte