👀배울 내용 요약
코틀린 언어는 함수형 패러다임을 지원하는 기능이 있습니다.
함수형 프로그래밍은 프로그램 코드를 불변 값을 변환하는 함수의 합성으로 구성할 수 있다는 아이디어를 바탕으로 합니다.
함수형 언어는 함수를 first class 값으로 취급합니다. -> 함수를 다른 일반적인 타입의 값과 똑같이 취급한다는 뜻입니다.
first class는 변수에 값을 대입하거나 변수에서 값을 읽을 수 있고 함수에 값을 전달하거나 함수가 값을 반환할 수 있다는 의미입니다.
이러한 성질은 함수인 값을 데이터와 마찬가지로 조작할 수 있는 고차 함수라는 함수를 저의 할 수 있게 해 주며, 코드 추상화와 합성이 더 쉽게 가능한 유연성을 제공해 준다고 합니다.
📕고차함수
fun aggregate(numbers: IntArray,op:(Int,Int)->Int):Int{
var result=numbers.firstOrNull()
?:throw IllegalArgumentException("Emty array")
println("${result}")
for(i in 1..numbers.lastIndex) {
println(op(result,numbers[i]))
result = op(result, numbers[i])
}
return result
}
fun sum(numbers : IntArray) =aggregate(numbers,{result,op->result+op})
fun max(numbers:IntArray)=aggregate(numbers,{result,op->if(op>result) op else result})
fun main(){
println("sum함수 실행 : ${sum(intArrayOf(1,2,3))}")
println("max함수 실행 : ${max(intArrayOf(1,2,3))}")
}
위 함수에서 op 파라미터가 다른 파라미터와 다른 점은 이 파라미터를 표현하는 타입이 함수 타입인 (Int, Int)-> Int라는 점뿐이다.
이 말은 이 op 파라미터는 Int값을 한쌍 받아서 Int를 결과로 내놓는 함수처럼 쓰인다.
sum()과 max()를 보면 aggregate를 호출하는 쪽에서는 함숫값을 표현하는 람다식을 인자로 넘긴다는 사실을 알 수 있다.
람다식은 기본적으로 단순한 형태의 문법을 사용해 정의하는 이름이 없는 지역 함수다.
{result, op->result+op}
result와 op는 함수 파라미터 역할을 하며 -> 다음에 오는 식은 결과를 계산하는 식이다. [return은 불필요함]
📕함수 타입
함수 타입은 함수처럼 쓰일 수 있는 값들을 표시하는 타입이다. 문법적으로 이런 타입은 함수 시그니처와 비슷하며, 다음과 같이 두 가지 부분으로 구성된다.
- 괄호로 둘러싸인 파라미터 타입 목록은 함숫값에 전달될 데이터의 종류와 수를 정의한다.
- 반환 타입은 함수 타입의 함숫값을 호출하면 돌려받게 되는 값의 타입을 정의한다.
반환 값이 없는 함수라도 함수 타입에서는 반환 타입을 반드시 명시해야 한다. 따라서 이런 경우는 Unit을 반환 타입으로 사용한다.
예를 들어 (Int, Int) -> Boolean이라는 타입은 인자로 정수를 한 쌍 받아서 결과로 Boolean 값을 계산하는 함수를 뜻한다.
함수 정의와는 다르게 함수 타입 표기에서는 인자 타입 목록과 반환 타입 사이를 :이 아닌 ->로 구분한다.
함숫값을 호출하는 다른 방법은 invoke() 메서드를 사용하는 것이다.
invoke() 메서드도 함수 타입의(괄호 안에 있는) 파라미터 목록과 똑같은 개수와 타입의 인자를 받는다.
ex) result=op.invoke(result, numbers [i])
💡함수가 인자를 받지 않는 경우에는 함수 타입의 파라미터 목록에 빈 괄호를 사용한다.
fun measureTime(action:() -> Unit): Long{
val start = System.nanoTime()
action()
return System.nanoTime()-start
}
💡파라미터 타입을 둘러싼 괄호는 필수이므로 함수 타입이 파라미터를 하나만 받거나 전혀 받지 않는 경우에도 괄호를 꼭 쳐야 한다.
val inc: (Int) -> Int = {n->n+1} // ok
val dec: Int-> Int={n->n-1} // Error
💡함수 타입의 값은 다른 타입이 쓰일 수 있는 모든 장소에서 사용할 수 있다.
fun main(){
val lessThan : (Int, Int)->Boolean= {a,b->a<b}
println(lessThan(1,2))
}
🛑여기서 만약 변수 타입을 생략한다면 컴파일러가 람다 파라미터의 타입을 추론할 수 없다.
val lessThan = {a, b->a <b} //error
💡이런 경우 파라미터의 타입을 명시하면 된다.
val lessThan = { a : Int, b: Int->a <b }
💡또 다른 타입과 마찬가지로 함수 타입도 날이 될 수 있는 타입으로 지정할 수 있습니다.
이럴 때는 함수 타입 전체를 괄호로 둘러싼 다음에 물음표를 붙인다.
fun measureTime(action : (()->Unit)? ):Long {
val start = System.nanoTime()
action?.invoke()
return System.nanoTime() - start
}
fun main(){
println(measureTime(null))
}
괄호로 함수 타입을 둘러싸지 않으면 물음표의 효과가 완전히 달라진다.
() -> Unit? 는 Unit? 타입의 값을 반환하는 함수를 표현하는 타입이다.
💡함수 타입을 다른 함수 타입 안에 내포시켜서 고차 함수의 타입을 정의할 수 있습니다.
fun main(){
val shifter: (Int) -> (Int) -> Int={n -> {i->i+n}}
val inc=shifter(1)
val dec=shifter(-1)
println(inc(10)) //11
println(dec(10)) //9
}
'Skils > Kotlin' 카테고리의 다른 글
[Kotlin]-정규표현식 (0) | 2023.08.10 |
---|---|
[Kotlin] - 코루틴 (0) | 2023.03.05 |
[Kotlin] 객체(Object) (0) | 2022.09.12 |
[Kotlin] 프로퍼티(Property) (0) | 2022.09.02 |
[Kotlin] 널 가능성 (0) | 2022.09.01 |