2010-08-25 17 views
78

Je sais que cette question a été soulevée plusieurs fois de différentes façons. Mais ce n'est toujours pas clair pour moi. Y a-t-il un moyen d'atteindre ce qui suit?scala tuple déballage

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

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

+0

Copie possible de [Comment appliquer une fonction à un tuple?] (Http://stackoverflow.com/questions/1987820/how-to-apply-a-function-to-a-tuple) – Suma

Répondre

95

C'est une procédure en deux étapes. Commencez par transformer foo en une fonction, puis appelez-la pour la faire fonctionner comme un tuple.

(foo _).tupled(getParams) 
+3

Ne serait-il pas plus propre? si Scala a juste pensé à des arguments comme Tuples pour commencer? –

+11

Oui, ce serait beaucoup plus propre si Scala unissait sa gestion des tuples et des listes d'arguments. D'après ce que j'ai entendu, il y a beaucoup de cas marginaux non évidents qui nécessiteraient une manipulation minutieuse pour que cela se produise. Pour autant que je sache, l'unification des tuples et des listes d'arguments ne figure pas sur la feuille de route de Scala pour le moment. –

+2

Juste pour ajouter, si foo est la méthode d'usine de l'objet compagnon, on pourrait utiliser (Foo.apply _) .nouspled (getParams) – RAbraham

17

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

EDIT:

Pour répondre à votre commentaire:

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

Dans ce cas, cette astuce ne fonctionnera pas.

Vous pouvez écrire une méthode usine dans l'objet compagnon de votre classe, puis obtenir la version triplée de sa méthode apply en utilisant 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 class es vous obtenez un objet compagnon avec une méthode apply gratuitement, et donc cette technique est plus pratique à utiliser avec case class es. Je sais que c'est beaucoup de duplication de code mais hélas ... nous n'avons pas de macros (pour l'instant)! ;)

+3

Dans le dernier exemple ici, vous pourriez raser un peu ... Objets compagnons pour l'affaire les classes étendent toujours le trait FunctionN approprié. Donc la dernière ligne pourrait être '' Person.tupled (("Rahul", "G")) '' Il est également pratique de le faire dans des objets compagnons écrits à la main. –

+0

@David: Édité, merci. :-) – missingfaktor

48

@ dave-griffith est mort.

Vous pouvez aussi appeler:

Function.tupled(foo _) 

Si vous voulez errer dans « façon plus d'informations que j'ai demandé » territoire, il existe aussi des méthodes intégrées dans les fonctions partiellement appliquées (et sur Function) pour le corroyage. 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> 

la version dans laquelle cari 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 uncurry/untuple si nécessaire. Function a builtins 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> 

1

Maintenant, vous pouvez implémenter foo et faire prendre un PARAM la classe Tuple2 comme ainsi.

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

J'apprécie quelques-unes des autres réponses qui étaient plus proches de ce que vous avez demandé, mais je l'ai trouvé plus facile pour un projet en cours d'ajouter une autre fonction qui convertit les paramètres de tuple dans les paramètres de division:

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