web-dev-qa-db-fra.com

scala Déballage de tuple

Je sais que cette question a été soulevée à plusieurs reprises de différentes manières. Mais ce n'est toujours pas clair pour moi. Existe-t-il un moyen d'atteindre les objectifs suivants.

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
}
89
scout

C'est une procédure en deux étapes. Transformez d'abord foo en fonction, puis appelez tupled dessus pour en faire une fonction de Tuple.

(foo _).tupled(getParams)
102
Dave Griffith

@ dave-griffith est mort.

Vous pouvez également appeler:

Function.tupled(foo _)

Si vous voulez vous promener dans "bien plus d'informations que ce que j'ai demandé", il existe également des méthodes intégrées aux fonctions partiellement appliquées (et sur Function) pour le curry. Quelques exemples d'entrées/sorties:

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>

Dans lequel la version au curry est invoquée avec plusieurs listes d'arguments:

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

Enfin, vous pouvez également désincurver/décupler si nécessaire. Function a des fonctions intégrées pour cela:

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>
53
Brendan W. McAdams

Function.tupled(foo _)(getParams) ou celle suggérée par Dave.

MODIFIER:

Pour répondre à votre commentaire:

Et si foo se trouve être le constructeur d'une classe?

Dans ce cas, cette astuce ne fonctionnera pas.

Vous pouvez écrire une méthode d'usine dans l'objet compagnon de votre classe, puis obtenir la version tuplée de sa méthode apply à l'aide de l'une des techniques susmentionnées.

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

Avec case classes vous obtenez gratuitement un objet compagnon avec une méthode apply, et donc cette technique est plus pratique à utiliser avec case classes.

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

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

Je sais que c'est beaucoup de duplication de code mais hélas ... nous n'avons pas (encore) de macros! ;)

19
missingfaktor

J'apprécie certaines des autres réponses qui étaient plus proches de ce que vous aviez demandé, mais j'ai trouvé plus facile pour un projet en cours d'ajouter une autre fonction qui convertit les paramètres Tuple en paramètres divisés:

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

Maintenant, vous pouvez implémenter foo et lui faire prendre un paramètre de la classe Tuple2 comme ça.

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)
1
Rejinderi