2. Functions in Scala
Functions in Scala¶
참고: https://www.baeldung.com/scala/functions
개요¶
- 부분 적용 함수 (partially-applied functions)
- 커링 (function currying)
- 부분 함수 (partial functions)
- 함수 전반
함수¶
- 함수는 일급 시민
- 함수가 매개변수로 전달, 리턴 가능
- 변수에 할당할 수 있음
- 그냥 값 처럼 타입을 지정할 수 있음
- def
- 매번 평가
- 메서드라고 부름
- 객체나 클래스 내에 정의해야 함.
- 클래스 인스턴스에서 implicit 참조가 있음
- 값이 아니며, 타입이 없음
- val
- 한번 평가 후 계속 씀
- function value
FunctionN의 타입 (N : 0 ~ 22)- 해당 trait 에 andThen, compose 등의 메서드가 정의되어 있음. (https://www.scala-lang.org/api/2.12.0/scala/Function1.html|)
val getNameLengthVal: String => Int = name => name.length val multiplyByTwoVal: Int => Int = num => num * 2 getNameLengthVal.andThen(multiplyByTwoVal) // 컴파일 잘 된다. def getNameLengthDef(name: String): Int = name.length def multiplyByTwoDef(num: Int): Int = num * 2 getNameLengthDef.andThen(multiplyByTwoDef) // 컴파일 안 돼! // 메서드를 Function Value로 변환하려면 이렇게 val getNameLengthFnValue = getNameLengthDef _ val multiplyByTwoFnValue = multiplyByTwoVal _ getNameLengthFnValue.andThen(multiplyByTwoFnValue) // 컴파일 잘 된다.
- 해당 trait 에 andThen, compose 등의 메서드가 정의되어 있음. (https://www.scala-lang.org/api/2.12.0/scala/Function1.html|)
부분 적용 함수 (Partially-Applied Functions)¶
- 아규먼트가 부분적으로 적용됨
- 일반 함수보다 구체적인 함수를 만들 수 있음. 반복적인 코드 피할 수 있음
- 함수 적용 시, 모든 파라미터에 대해 아규먼트를 넘기지 않고, 몇 개만 넘기고 나머지 빈칸
- 이러면 스칼라는 남은 파라미터는 순서대로 넣어주면 되는 새로운 함수를 리턴
- 부분 적용 함수는 항상 새로운 함수 반환해!
- 원본 함수는 정말 아규먼트가 fully applied 된 경우에만 평가된다.
이렇게 하면 반복적인 코드가 개선이 된다.¶
def createUrl(protocol: String, domain : String) : String = {
s"$protocol$domain"
}
val baeldung = createUrl("https://","www.baeldung.com")
val facebook = createUrl("https://","www.facebook.com")
val twitter = createUrl("https://","www.twitter.com")
val google = createUrl("https://","www.google.com")
def createUrl(protocol: String, domain : String) : String = {
s"$protocol$domain"
}
val withHttpsProtocol: String => String = createUrl("https://", _: String)
val withHttpProtocol: String => String = createUrl("http://", _: String)
val withFtpProtocol: String => String = createUrl("ftp://", _: String)
val baeldung = withHttpsProtocol("www.baeldung.com")
val facebook = withHttpsProtocol("www.facebook.com")
val twitter = withHttpsProtocol("www.twitter.com")
val google = withHttpsProtocol("www.google.com")
- 많은 보일러 플레이트 함수들을 개선할 수 있음!
함수 커링¶
- 커링된 함수는 여러개의 아규먼트 그룹을 하나씩 받도록 함
- 커링된 함수는 첫번째 아규먼트 그룹을 받아, 그 다음 아규먼트 그룹을 받는 함수를 리턴.
- 부분 적용 함수와 비슷. (하지만 기술적으로 다름)
- 함수 커링은...
- 함수 (A, B, C, D)를 (A => (B => (C => D)))
-
근데 이거 굳이 왜 함?
-
Future를 보면, apply 메서드가 커링 함수를 씀
- 두번째 파라미터 그룹이
implicit execution context를 받아서 넘김!
- 두번째 파라미터 그룹이
-
제네릴 쓸 때 유용
- 컴파일러는 다른 매개변수 그룹에 있어야 추론하여 컴파일 할 수 있음
- 타입 추론은 매개변수 그룹
왼 -> 오로 흐름.def withListItems[T](list : List[T],f : T => Unit) : Unit = { list match { case Nil => () case h :: t => f(h) withListItems(t,f) } } withListItems(List(1,2,3,4), number => println(number + 2)) // does not compile def withListItems[T](list : List[T])(f : T => Unit) : Unit = { list match { case Nil => () case h :: t => f(h) withListItems(t)(f) } } withListItems(List(1,2,3,4))(number => println(number + 2)) // compiles
-
부분 함수¶
- Partially applied function 은 입력 값의 하위 집합에 대해서만 작동하는 함수.
- trait
PartialFunction이 있음val isWorkingAge: PartialFunction[Int, String] = new PartialFunction[Int, String] { override def isDefinedAt(x: Int): Boolean = if (x > 18) true else false override def apply(v1: Int): String = { if (isDefinedAt(v1)) { "WORK!" } else { "NO WORK!" } } } // 이렇게 사용 가능 val isWorkingAge : PartialFunction[Int,String] = { case age if age >= 18 && age <= 60 => s"You are $age years old and within working age" case other => s"You are $other years old and not within working age" }
- isDefinedAt 어디갔나 하겠지만, 처리 못하는 케이스에 대해서 간주하면 구현이 되나봄
orElse,andThen등 스칼라에서는 많이 쓰임