[Kotlin] 함수형 프로그래밍
함수형 프로그래밍
-
함수형 프로그래밍
코드 간략, 테스트나 재사용성 증가
람다식, 고차 함수를 사용해 구성
순수 함수
-
객체 지향 프로그래밍
클래스, 객체들의 관계를 중심으로 코드 작성이 이루어짐
-
순수 함수
부작용(side-effect)가 없는 함수
→ 동일한 입력 인자에 대해서는 항상 같은 결과를 출력, 반환한다
fun sum(a:Int, b: Int): Int{ return a+b }
동일한 인자 a,b입력받아 항상 a+b를 출력
조건 ⇒ 같은 인자에 대해 항상 같은 값을 반환
⇒ 함수 외부의 어떤 상태도 바꾸지 않음
❗ 그렇다면 순수함수가 아닌 것은?
const val num = 5 fun main(){ val result = test(1,2) println(result) } fun result(a: Int, b: Int): Int { return a+b+num }
다음 result라는 함수는 입력값과 무관하게 항상 외부의 값을 사용하고 있기 때문에, 동일한 a,b가 들어온다고 해도 외부의 값이 변경되면 값이 변경될 수 있으므로 순수함수가 될수 없음 !
순수함수를 사용하는 이유
- 입력과 내용을 분리하고 모듈화 하므로 재사용성 높아짐
- 함수의 값을 추적하고 예측할 수 있기 때문에 테스트, 디버깅 등이 유리함
람다식
: 일종의 익명함수, 이름 없이사용 및 실행이 가능
→ 고차 함수에서 인자로 넘기거나 결과값으로 반환 등을 할 수 있음
// (Int, Int) -> Int : 람다식의 선언 자료형
// {a,b 람다식의 매개 변수 -> a * b 람다식의 처리 내용}
val multi : (a:Int, b:Int) -> Int = {a,b -> a*b} //변수를 함수처럼 사용 가능
val multi = {a: Int, b: Int -> a*b}// 이렇게 간단하게 쓸 수 있음
multi(2,3)
- 매개변수가 없을때
val greet: () -> Unit = { print("hi") } //리턴값이 없을땐 Unit 표시
- 매개변수가 하나일 때
val add: (Int) -> Int = { it + 1} // it으로 쓸 수 있음
- 두줄일때 !
val lambda : () -> Boolean = {
println("lambda function")
true //위에 그냥 출력하고 true 를 반환
}
-
- 값에 의한 호출
-
함수가 인자로 전달될 경우, 람다식 함수는 값으로 처리되어 그 즉시 함수가 수행된 후 값을 전달
fun main(){
val reuslt = callByValue(Lambda()) //람다식 함수를 호출
println(result) //3
}
fun callByValue(b:Boolean):Boolean{ //otherLambda함수 통째로 들어감
println("callByValue function") // 2
return b
}
fun Lambda: ()-> Boolean = {
println("Lambda function")// 1
true
}
-
- 이름을 사용한 호출
-
소괄호 없이 이름으로만 호출 → 람다식 타입으로 써져 있기 때문에, otherLambda 함수 내용이 통째로 callByName의 매개변수로 들어감 ⇒ 해당 함수가 호출되기 전까지(return b()) 람다식 함수가 실행되지 않음
fun main(){
val reuslt = callByName(otherLambda)//람다식 이름으로 호출
println(result) //3
}
fun callByName(b: ()-> Boolean):Boolean{ //otherLambda함수 통째로 들어감
println("callByName function") // 1
return b()
}
fun otehrLambda: ()-> Boolean = {
println("otherLambda function")//2
true
}
-
- 참조에 의한 호출
-
sum이라는 함수는 일반 함수지만, 람다식에 존재하는 매개변수와 반환값과 일치한다면 참조방식으로 사용할 수 있음
fun sum(x :Int, y:Int) = x + y
fun funcParam(a: Int, b: Int, c: (Int,Int) -> Int): Int {
return c(a,b)
}
funcParam(3,2, ::sum)
fun sum(a: Int, b: Int) = a + b
fun text(a: String, b: String) = "Hi! $a $b"
fun funcParam(a: Int, b: Int, c: (Int, Int) -> Int): Int {
return c(a, b)
}
fun hello(body: (String, String) -> String): Unit {
println(body("Hello", "World"))
}
// 1. 인자와 반환값이 있는 함수
val res1 = funcParam(3, 2, ::sum)
println(res1)
// 2. 인자가 없는 함수
hello(::text) // 반환값이 없음
// 3. 일반 변수에 값처럼 할당
val likeLambda = ::sum
println(likeLambda(6,6))
일급 객체
일급 객체는 함수의 인자로 전달할 수 있다.
일급 객체는 함수의 반환값에 사용할 수 있다.
일급 객체는 변수에 담을 수 있다.
⇒ 코틀린에서 함수는 1급 객체(1급 함수)다.
고차 함수
다른 함수를 인자로 사용하거나 함수를 결과값으로 반환하는 함수
fun main(){
println(highFunc({a, b -> a + b}, 10, 20))
}
fun highFunc(sum: (Int, Int) -> Int, a:Int, b:Int) : Int{
return sum(a,b)
}
fun sum(a: Int, b: Int) = a+b
fun mul(a: Int, b: Int): Int{
return a * b
}
fun main(){
val result = mul(sum(2,3), 5)//함수의 특정 인자를 함수로 넘겨줌
print(result)
}
//fun funcFunc(a: Int, b: Int): Int{
// return sum(a,b)
//}
fun funcFunc(a :Int, b:Int) = sum(a,b) //함수 내부의 반환형태를 함수로 넘겨줌
- 다양한 고차함수 표현법
fun inc(x: Int) : Int{
return x + 1
}
fun high(name:String, body: (Int)-> Int):Int{
println("name: $name")
val x = 0
return body(x)
}
// 함수를 이용한 람다식
val result = high("Sean", { x -> inc(x + 3) })
// 소괄호 바깥으로 빼내고 생략
val result2 = high("Sean") { inc(it + 3) }
// 매개변수 없이 함수의 이름만 사용할 때
val result3 = high("Kim", ::inc)
// 람다식 자체를 넘겨 준 형태
val result4 = high("Sean") { x -> x + 3 }
// 매개변수가 한 개인 경우 생략
val result5 = high("Sean") { it + 3 }
익명 함수
: 이름이 없는 함수
fun (x:Int, y:Int): Int = x + y
val add: (Int, Int) -> Int = fun(x,y) = x + y
val result = add(10,2)
val add = fun(x: Int, y: Int) = x + y //익명함수
val add = {x: Int, y: Int -> x + y} //람다식
❗ 람다식과 익명함수의 차이
익명함수에서는return, break, continue가 사용 가능하지만, 람다식에서는 사용하기 어려움
인라인 함수
: 함수가 호출되는 곳에 내용을 모두 복사, 함수의 분기 없이 처리 → 성능 증가
inline fun shortFunc(){
println("hi")
}
fun main(){
shortFunc() // 왔다갔다 이동없이, println("hi")가 바로 복사됨
}
하지만 shortFunc()의 내용이 길다면 복사하는데 시간이 오래걸리기 때문에, 보통 람다식 매개변수를 가지고있다고 한다.
inline fun shortFunc(a:Int, b: (Int)-> Unit){
println("hi")
out(a)
}
fun main(){
// shortFunc(3, {a -> println("a: $a")}) 왔다갔다 이동없이, println("hi")가 바로 복사됨
shortFuc(3) {println("$it")}
}
확장 함수
: 클래스의 멤버 함수를 외부에서 더 추가할 수 있고, 기존의 표준라이브러리를 수정하지 않고도 확장할 수 있음
만약, 만들고자하는 확장함수와 동일한 이름의 멤버함수가 존재한다면 , 항상 확장함수보다 멤버 메서드가 우선으로 호출됨 !
fun 확장대상.함수명(매개변수, …) : 반환값 {
return 값
}
fun main(){
val source = "Hello World!"
val target = "kotlin"
println(source.getLongString(target))
}
fun String.getLongString(target: String) : String =
if (this.length > target.lenght) thi else target //this = source
Comments