web-dev-qa-db-ja.com

scala Tuple unpacking

私はこの質問がさまざまな方法で何度も出てきたことを知っています。しかし、私にはまだ明確ではありません。以下を達成する方法はありますか。

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

これは2段階の手順です。最初にfooを関数に変換し、次にそれをタプルして呼び出してTupleの関数にします。

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

@ dave-griffithは死んでいます。

以下を呼び出すこともできます。

Function.tupled(foo _)

「私が要求したよりも多くの情報」領域に行きたい場合、カリー化のために部分的に適用された関数(およびFunction)に組み込まれたメソッドもあります。いくつかの入力/出力の例:

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>

カリー化されたバージョンは、複数の引数リストで呼び出されます:

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

最後に、必要に応じて、カレー/アンタプルもできます。 Functionにはこのためのビルトインがあります:

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

Function.tupled(foo _)(getParams)またはDaveによって提案されたもの。

編集:

コメントに返信するには:

fooが何らかのクラスのコンストラクターである場合はどうなりますか?

その場合、このトリックは機能しません。

クラスのコンパニオンオブジェクトにファクトリメソッドを記述し、前述の手法のいずれかを使用して、そのapplyメソッドのタプルバージョンを取得できます。

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

case classes applyメソッドを持つコンパニオンオブジェクトを無料で取得できます。したがって、この手法はcase classes。

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

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

私はそれが多くのコードの重複であることを知っていますが、悲しいかな...私たちにはマクロがありません(まだ)! ;)

19
missingfaktor

あなたが求めたものに近い他の回答のいくつかを感謝しますが、現在のプロジェクトがTupleパラメータを分割パラメータに変換する別の関数を追加する方が簡単であることがわかりました:

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

これで、fooを実装して、Tuple2クラスのパラメーターを取得することができます。

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