scala tuple membongkar

95

Saya tahu pertanyaan ini sering muncul dengan cara yang berbeda. Tapi masih belum jelas bagi saya. Apakah ada cara untuk mencapai hal berikut.

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
}
pramuka
sumber
11
Bagaimana jika foo kebetulan menjadi konstruktor dari beberapa kelas?
pramuka
Kemungkinan duplikat dari Bagaimana menerapkan fungsi ke tupel?
Suma

Jawaban:

107

Ini adalah prosedur dua langkah. Pertama-tama ubah foo menjadi fungsi, lalu panggil tuple di atasnya untuk menjadikannya fungsi tupel.

(foo _).tupled(getParams)
Dave Griffith
sumber
3
Bukankah lebih bersih jika Scala hanya memikirkan argumen sebagai Tuple untuk memulai?
Henry Story
12
Ya, akan jauh lebih bersih jika Scala akan menyatukan penanganan tupel dan daftar argumen. Dari apa yang saya dengar, ada banyak kasus tepi yang tidak jelas yang memerlukan penanganan hati-hati untuk mewujudkannya. Sejauh yang saya tahu, penyatuan tupel dan daftar argumen tidak ada di peta jalan Scala saat ini.
Dave Griffith
2
Sebagai tambahan, jika foo adalah metode pabrik dari objek pendamping, seseorang dapat menggunakan (Foo.apply _]. Tupled (getParams)
RAbraham
56

@ dave-griffith sudah mati.

Anda juga dapat menghubungi:

Function.tupled(foo _)

Jika Anda ingin menjelajahi wilayah "jauh lebih banyak informasi daripada yang saya minta", ada juga metode yang dibangun ke dalam fungsi yang diterapkan sebagian (dan Functionseterusnya) untuk kari. Beberapa contoh masukan / keluaran:

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>

Di mana versi curried dipanggil dengan beberapa daftar argumen:

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

Terakhir, Anda juga dapat membatalkan / melepas jika perlu. Functionmemiliki bawaan untuk ini:

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
sumber
20

Function.tupled(foo _)(getParams)atau yang disarankan oleh Dave.

EDIT:

Untuk menanggapi komentar Anda:

Bagaimana jika foo kebetulan menjadi konstruktor dari beberapa kelas?

Dalam hal ini, trik ini tidak akan berhasil.

Anda dapat menulis metode pabrik di objek pendamping kelas Anda dan kemudian mendapatkan versi tuple dari applymetode tersebut menggunakan salah satu teknik yang disebutkan di atas.

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

Dengan case classes Anda mendapatkan objek pendamping dengan applymetode gratis, dan dengan demikian teknik ini lebih nyaman digunakan dengan case classes.

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

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

Saya tahu itu banyak duplikasi kode tetapi sayangnya ... kami belum memiliki makro (belum)! ;)

missingfaktor
sumber
3
Dalam contoh terakhir di sini, Anda dapat mengurangi sedikit ... Objek pendamping untuk kelas kasus selalu memperluas sifat FunctionN yang sesuai. Jadi baris terakhir bisa jadi Person.tupled(("Rahul", "G")) berguna untuk melakukan ini pada objek pendamping yang ditulis tangan juga.
David Winslow
3

Saya menghargai beberapa jawaban lain yang lebih dekat dengan apa yang Anda minta, tetapi saya merasa lebih mudah untuk proyek saat ini untuk menambahkan fungsi lain yang mengubah parameter tupel menjadi parameter terpisah:

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

Sekarang, Anda dapat mengimplementasikan foo dan membuatnya mengambil parameter kelas Tuple2 seperti itu.

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
sumber