내가 유지하는 Scala Style Guide의 Multiple Parameter Lists 에 대해 논의 하고 있습니다. 커링 에는 두 가지 방법이 있다는 것을 깨닫게 되었고 사용 사례가 무엇인지 궁금합니다.
def add(a:Int)(b:Int) = {a + b}
// Works
add(5)(6)
// Doesn't compile
val f = add(5)
// Works
val f = add(5)_
f(10) // yields 15
def add2(a:Int) = { b:Int => a + b }
// Works
add2(5)(6)
// Also works
val f = add2(5)
f(10) // Yields 15
// Doesn't compile
val f = add2(5)_
스타일 가이드는 그것들이 분명히 같지 않은데도 동일하다고 잘못 암시합니다. 가이드는 생성 된 카레 기능에 대해 지적하려고 노력하고 있으며, 두 번째 형태는 “책별”카레 링이 아니지만 여전히 첫 번째 형태와 매우 유사합니다. _
)
이러한 양식을 사용하는 사람들로부터 한 양식을 다른 양식보다 사용할 때에 대한 합의는 무엇입니까?
답변
다중 매개 변수 목록 방법
유형 추론
여러 매개 변수 섹션이있는 메서드는 첫 번째 섹션의 매개 변수를 사용하여 후속 섹션의 인수에 대해 예상되는 형식을 제공 할 형식 인수를 추론함으로써 로컬 형식 유추를 지원하는 데 사용할 수 있습니다. foldLeft
표준 라이브러리에 이것의 표준적인 예가 있습니다.
def foldLeft[B](z: B)(op: (B, A) => B): B
List("").foldLeft(0)(_ + _.length)
이것이 다음과 같이 쓰여졌다면 :
def foldLeft[B](z: B, op: (B, A) => B): B
보다 명시적인 유형을 제공해야합니다.
List("").foldLeft(0, (b: Int, a: String) => a + b.length)
List("").foldLeft[Int](0, _ + _.length)
유창한 API
다중 매개 변수 섹션 메소드의 또 다른 용도는 언어 구조처럼 보이는 API를 만드는 것입니다. 호출자는 괄호 대신 중괄호를 사용할 수 있습니다.
def loop[A](n: Int)(body: => A): Unit = (0 until n) foreach (n => body)
loop(2) {
println("hello!")
}
M 매개 변수 섹션이있는 메서드에 N 인수 목록 적용 (여기서 N <M)은를 사용하여 명시 적으로 _
또는 FunctionN[..]
. 이것은 안전 기능입니다. 배경은 Scala References의 Scala 2.0에 대한 변경 노트를 참조하십시오.
카레 기능
커리 함수 (또는 간단히 함수를 반환하는 함수)는 N 인수 목록에 더 쉽게 적용 할 수 있습니다.
val f = (a: Int) => (b: Int) => (c: Int) => a + b + c
val g = f(1)(2)
이 사소한 편의는 때때로 가치가 있습니다. 함수는 유형 매개 변수가 될 수 없으므로 경우에 따라 메서드가 필요합니다.
두 번째 예는 함수를 반환하는 하나의 매개 변수 섹션 메서드 인 하이브리드입니다.
다단계 계산
카레 기능이 유용한 다른 곳은 어디입니까? 다음은 항상 나타나는 패턴입니다.
def v(t: Double, k: Double): Double = {
// expensive computation based only on t
val ft = f(t)
g(ft, k)
}
v(1, 1); v(1, 2);
결과를 f(t)
어떻게 공유 할 수 있습니까? 일반적인 해결책은 다음의 벡터화 된 버전을 제공하는 것입니다 v
.
def v(t: Double, ks: Seq[Double]: Seq[Double] = {
val ft = f(t)
ks map {k => g(ft, k)}
}
추한! 우리는 관련이없는 문제를 얽히게 한 – 계산 g(f(t), k)
의 순서를 통해 매핑 ks
.
val v = { (t: Double) =>
val ft = f(t)
(k: Double) => g(ft, k)
}
val t = 1
val ks = Seq(1, 2)
val vs = ks map (v(t))
함수를 반환하는 메서드를 사용할 수도 있습니다. 이 경우 좀 더 읽기 쉽습니다.
def v(t:Double): Double => Double = {
val ft = f(t)
(k: Double) => g(ft, k)
}
그러나 여러 매개 변수 섹션이있는 메소드로 동일한 작업을 시도하면 멈춰 있습니다.
def v(t: Double)(k: Double): Double = {
^
`-- Can't insert computation here!
}
답변
메서드가 아닌 함수 만 카레 할 수 있습니다. add
메서드이므로 _
함수로 강제 변환하려면이 필요합니다. add2
함수를 반환하므로는 _
불필요 할뿐만 아니라 여기서 의미가 없습니다.
다른 방법과 기능 (예 : JVM의 관점에서) 얼마나 고려, 스칼라는 꽤 좋은 작업 그들 사이의 경계를 모호하게하고 대부분의 경우에 “옳은 일을”일을 수행하지만 거기에 있다 차이, 그리고 때때로 당신은 단지 필요 그것에 대해 알고 있습니다.
답변
두 개의 매개 변수가 def add(a: Int)(b: Int): Int
있는 메소드를 정의하기 만하면 그 차이를 파악하는 것이 도움이 될 것 입니다.이 두 매개 변수 만 두 개의 매개 변수 목록으로 그룹화됩니다 (다른 주석에서 그 결과를 참조하십시오). 사실, 그 방법은 int add(int a, int a)
자바 (Scala가 아님!)에 관한 것입니다. 을 작성할 때 add(5)_
그것은 단지 함수 리터럴 일뿐입니다 { b: Int => add(1)(b) }
. 반면에 add2(a: Int) = { b: Int => a + b }
매개 변수가 하나만있는 메소드를 정의하면 Java의 경우 scala.Function add2(int a)
. add2(1)
Scala로 작성 하는 것은 (함수 리터럴과 반대되는) 단순한 메서드 호출 일뿐입니다.
또한 모든 매개 변수를 즉시 제공하는 경우 add
보다 (잠재적으로) 오버 헤드가 적습니다 add2
. JVM 수준에서로 add(5)(6)
변환되는 것처럼 개체가 생성 add(5, 6)
되지 않습니다 Function
. 반면 에은 add2(5)(6)
먼저를 포함하는 Function
객체를 5
만든 다음이를 호출 apply(6)
합니다.