스칼라 튜플 풀기


94

나는이 질문이 다른 방식으로 여러 번 나온다는 것을 알고 있습니다. 하지만 아직 명확하지 않습니다. 다음을 달성하는 방법이 있습니까?

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
foo가 어떤 클래스의 생성자라면 어떻게 될까요?
스카우트

답변:


107

2 단계 절차입니다. 먼저 foo를 함수로 변환 한 다음 tupled를 호출하여 튜플의 함수로 만듭니다.

(foo _).tupled(getParams)

3
Scala가 인수를 튜플로 생각하면 더 깨끗하지 않을까요?
Henry Story

12
예, Scala가 튜플 및 인수 목록 처리를 통합한다면 훨씬 더 깔끔 할 것입니다. 내가들은 바에 따르면, 그렇게하기 위해서는 신중한 처리가 필요한 불명확 한 가장자리 케이스가 많이 있습니다. 내가 아는 한, 튜플과 인수 목록의 통합은 현재 스칼라 로드맵에 없습니다.
Dave Griffith

2
추가하기 만하면 foo가 컴패니언 객체의 팩토리 메서드 인 경우 (Foo.apply _). tupled (getParams)
RAbraham

55

@ dave-griffith는 죽었습니다.

다음으로 전화 할 수도 있습니다.

Function.tupled(foo _)

"내가 요청한 것보다 더 많은 정보"영역을 헤매고 싶다면 Function카레를 위해 부분적으로 적용된 기능 (및 on )에 내장 된 방법도 있습니다 . 몇 가지 입력 / 출력 예 :

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>

curried 버전은 여러 인수 목록으로 호출됩니다.

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>


20

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)

코드 중복이 많은 것을 알고 있지만 아쉽게도 매크로가 없습니다 (아직)! ;)


3
여기의 마지막 예제에서 약간의 면도를 할 수 있습니다. 케이스 클래스를위한 컴패니언 객체는 항상 적절한 FunctionN 특성을 확장합니다. 그래서 마지막 줄은 Person.tupled(("Rahul", "G")) 손으로 쓴 컴패니언 개체에서도이 작업을 수행하는 것이 편리합니다.
David Winslow

3

요청한 내용에 더 가까운 다른 답변에 감사하지만 현재 프로젝트에서 튜플 매개 변수를 분할 매개 변수로 변환하는 다른 함수를 추가하는 것이 더 쉽다는 것을 알았습니다.

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

1

이제 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)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.