부분 적용 함수(partially applied function)에 대한 예시이다. 마치 함수처럼 사용할 수 있다.
def test(s1: String)(s2: String) = s1 + s2
val a = test("s1")
println(a)
이렇게 하면 에러가 발생한다.
Error:(10, 15) missing argument list for method test in object Main
Unapplied methods are only converted to functions when a function type is expected.
You can make this conversion explicit by writing `test _` or `test(_)(_)` instead of `test`.
val a = test("s1")
에러가 발생하지 않도록 하려면 다음처럼 _를 추가해야 한다.
def test(s1: String)(s2: String) = s1 + s2
val a = test("s1") _
println(a)
실제 테스트 결과를 출력하면 다음과 같다.
def test(s1: String)(s2: String) = s1 + s2
val a = test("s1") _
println(a("s2"))
만약 매개변수가 3개라면 _(언더바)를 2개를 써야할까? 하나면 쓰면 된다. _는 나머지를 가르키는 대명사 역할을 한다.
def test(s1: String)(s2: String)(s3: String) = s1 + s2 + s3
val a = test("s1") _
println(a)
만약 다음과 같은 형태를 사용할 수 있다.
def test(s1: String) = (s2: String) => s1 + s2
val a = test("s1")
println(a)
언커링하려면 다음과 같다.
def test(s1: String, s2: String) = s1 + s2
val curried = (test _).curried
println(curried("s1")("s2"))
println(test("s1", "s2"))
결과는 다음과 같다.
s1s2
s1s2
curried함수는 Function2 트레이트의 함수로서 정의되어 있는 함수이다.
/** Creates a curried version of this function.
*
* @return a function `f` such that `f(x1)(x2) == apply(x1, x2)`
*/
@annotation.unspecialized def curried: T1 => T2 => R = {
(x1: T1) => (x2: T2) => apply(x1, x2)
만약 커링함수를 언커링할 수 있다.
val uncurried = Function.uncurried(curried)
println(uncurried("s1", "s2"))
함수와 콜렉션를 받는 함수라면 다음처럼 사용할 수 있다.
object MyCombinator {
def foreach[A, U](f: A => U)(list: List[A]): Unit = list foreach f
}
val printX = (s: String) => println(s)
val f = MyCombinator.foreach(printX) _
f(List("1", "2"))
결과는 다음과 같다.
1
2
다음은 부분 함수이다. PartialFunction을 사용한다. 부분 적용 함수와 완전히 다른 형태이다. 입력 값이 일정 범위에 있는지를 정의할 수 있는 함수 정도(수학적인 부분을 의미하는지 알려주는 함수)가 될 것이다. 따라서 case 문으로 많이 사용된다.
val one: PartialFunction[Int, String] = { case 1 => "one" }
println(one.isDefinedAt(1))
println(one.isDefinedAt(2))
println(one(1))
결과는 다음과 같다.
true
false
PartialFunction의 또 다른 예시이다.
val div: PartialFunction[(Double, Double), Double] = {
case (x, y) if y != 0 => x /y
}
println(div.isDefinedAt(1, 1))
println(div.isDefinedAt(2, 1))
println(div(1, 1))
}
결과는 다음과 같다.
true
true
1.0
PartialFunction는 case문 아니면 에러가 발생한다. 다음과 같은 코드에 컴파일 에러가 발생한다.
val one: PartialFunction[Int, String] = { "" }
Error:(9, 45) type mismatch;
found : String("")
required: PartialFunction[Int,String]
val one: PartialFunction[Int, String] = { "" }
항상 case 문이 있어야 하지만, 다음 코드는 컴파일 에러가 발생하지 않는다. 정의대로 구현했기 때문이다.
val one = new PartialFunction[Int, String] {
def apply(d: Int) = ""
def isDefinedAt(d: Int) = d != 0
}
PartialFunction 트레이트와 PartionFuction 오브젝트가 존재한다.
trait PartialFunction[-A, +B] extends (A => B) { self =>
import PartialFunction._ ..
object PartialFunction {
참고로 PartialFunction은 예외를 발생하지 않는다.
val f: PartialFunction[String, String] = { case "ping" => "pong"}
val g: PartialFunction[List[Int], String] = {
case Nil =>"one"
case x :: rest =>
rest match {
case Nil => "two"
}
}
패턴매칭에 맞으면 true/false를 리턴한다.
println(Lists.f.isDefinedAt("ping"))
println(Lists.g.isDefinedAt(List(1,2,3)))
'scala' 카테고리의 다른 글
[scala] for 내장 (0) | 2016.12.08 |
---|---|
[scala] try-catch/Try-match/Either/Validation (0) | 2016.12.06 |
[scala] 꼬리 재귀(tail recursion)와 @tailrec (0) | 2016.12.05 |
[scala] Future말고 Promise (0) | 2016.11.27 |
[scala] Future 2 (0) | 2016.11.23 |