Uknow's Lab.
article thumbnail

 

 

함수형 프로그래밍 (Functional Programming)

 

함수형 프로그래밍이란?

데이터 처리를 위해 수학적 함수의 계산으로 취급하고, 가변 데이터를 멀리하며 부수효과를 줄인 일종의 프로그래밍 패러다임이다.

 

이러한 함수형 프로그래밍은 무엇을 하는지 선언하는 형식에 가깝다 하여 선언형 프로그래밍이라고도 합니다.

기존의 절차적/객체지향 프로그래밍은 무엇을 할 지 명령한다 하여 명령형 프로그래밍이라고 하죠.

 

함수형 프로그래밍은 과정보다는 결과를,

어떻게(How) 할 지 보다는, 무엇(What)을 할 지에 포커스를 둡니다.

 

최신의 언어들 (Scala, Swift, Python)은 함수형 프로그래밍을 지원하며, Kotlin 역시 함수형 프로그래밍을 지원합니다.

자바는 자바 8버전부터 함수형 프로그래밍을 지원하기 시작했습니다.

 

 

함수형 프로그래밍의 특징

일급 객체 (First Class Citizen)

또 어려운 말이 나왔습니다. 어떻게 설명해야 할 지도 모르겠습니다. 저도 처음 들어봐요.

 

https://en.wikipedia.org/wiki/First-class_citizen

 

First-class citizen - Wikipedia

From Wikipedia, the free encyclopedia Concept in programming language design In programming language design, a first-class citizen (also type, object, entity, or value) in a given programming language is an entity which supports all the operations generall

en.wikipedia.org

 

한글 위키피디아에서는 관련 내용을 찾지 못하여 영문 위키피디아를 참고했습니다.

 

짧게 요약해보자면, 함수형 프로그래밍에서의 함수는 최상위 구성요소가 되며,

일급 객채는 아래와 같은 특성을 지니고 있습니다.

  • 함수를 함수의 파라미터로써 넘겨줄 수 있다
  • 반환값이 함수가 될 수 있다
  • 함수를 변수에 할당할 수 있다

 

웹 프로그래밍을 배울 때, 자바스크립트를 얕게나마 공부해본적이 있는데,

변수에 함수를 할당하는 것을 보고 신기했던 기억이 납니다.

 

코틀린 역시 함수형 프로그래밍을 지원하며 위 특성을 모두 가지고 있습니다.

 

 

 

순수 함수 (Pure Function)

순수함수란, 부수효과(Side - Effect)가 없는 함수입니다.

 

부수효과(Side - Effect)란, 함수에서 값을 반환하는 것 외에 발생되는 부수적인 효과를 말합니다.

그리고, 순수함수란 이러한 부수효과가 없는,

즉, 함수 외부에서 영향을 받거나, 외부에 영향을 주지 않는 함수입니다.

외부로부터의 영향이 없으므로, 같은 인자를 넣어주면 항상 같은 값이 나와야 합니다.

 

// 부수효과 발생

var n = 5

fun add(a:Int, b:Int) :Int{
	return a + b + n
}


fun main() {
	println(add(10,10))
	n = 10
	println(add(10,10))
}

// 출력
25
30



// 부수효과 X

fun add(a:Int, b:Int) :Int {
	return a + b
}

fun main() {
	println(add(10,10))
	println(add(10,10))
}

// 출력
10
10

 

위의 코드는 전역변수인 n의 값에 영향을 받기 때문에,

같은 인자를 넣어줌에도 반환값이 25, 30으로 달라지는 것을 볼 수 있습니다.

 

반면, 아래 코드의 경우 외부의 값에 영향을 받지 않기 때문에,

같은 인자에 대해 늘 같은 반환값을 가집니다.

 

 

선언형

 

val arr = arrayOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)

여기 배열이 하나 있습니다.

 

저는 이 배열에서

  1. arr에서 짝수만 걸러낸 다음
  2. 각 원소를 + 2 씩 해주고
  3. 각 원소를 제곱한 뒤
  4. 모두 다 더한 값을 출력

해보고 싶습니다.

 

명령형 프로그래밍에서 하려면 어떻게 해야 할까요?

 

 

명령형 프로그래밍

val arr = arrayOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)

// 명령형 프로그래밍
var sum = 0
for (i in arr) {
    if (i % 2 == 0) {
        val temp = i + 2
        val temp2 = temp * temp
        sum += temp2
    }
}

println(sum)

 

사실 조금 귀찮을 뿐이지, for과 if를 적절히 사용하면 그리 어렵지 않게 구현할 수 있습니다.

그럼, 이를 함수형 프로그래밍으로 구현하려면 어떻게 해야 할까요?

 

 

함수형 프로그래밍

val arr = arrayOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)

// 함수형 프로그래밍
println(arr.filter { it % 2 == 0 }
        .map { it + 2 }
        .map { it * it }
        .sum())

 

filter는 배열의 원소를 돌며 특정 조건을 만족하는 원소들만 추출을,

map은 배열의 각 원소에 접근하여 가공을,

sum은 모든 원소를 합하는 역할을 합니다.

 

각 함수들을 보고, 무슨 역할을 하는지 한 눈에 보고 파악하기 더 수월해진 것 같죠?

 

 

함수형 프로그래밍의 장점

  • 코드가 간결해짐
  • 각 기능을 모듈화 (생산성 증대 및 유지보수 원활)
  • 불변성 제공 및 부수효과 방지
    • 이는 멀티 스레딩 환경에서 더욱 효과적
  • 코드의 재사용성 증가
  • 무엇을 할 지 선언하는 방식이므로, 가독성이 높아짐

 

 

장점이 있으면 단점도 있다

  • 부수효과를 가지지 않아 오직 함수형 프로그래밍만으로 프로그램을 개발하기 어려울 수 있음
  • 전체 배열을 순회하며 명령형 프로그래밍에 비해 퍼포먼스가 낮을 수 있음
    • 위 예제에서 for문의 경우 한 번씩 원소를 돌지만
    • 함수형 프로그래밍의 경우 filter, map, map, sum 총 네 번의 루프를 돔

 

 

함수형 프로그래밍 (1) 마침

프로그래밍 패러다임은

절차지향 프로그래밍 -> 객체지향 프로그래밍 -> 함수형 프로그래밍 순으로 떠오르고 있습니다.

 

하지만, 함수형 프로그래밍에서 객체지향 프로그래밍이 불가능한건 아닙니다.

이 둘은 서로 대척점에 있는 관계가 아니며,

뜨거운 아메리카노 <-> 차가운 아메리카노 보다는

밀크티와 펄추가의 관계와 가깝습니다.

 

함수형 프로그래밍 (2)에서는 직접 함수형 프로그래밍을 코딩해봅시다.

profile

Uknow's Lab.

@유노 Uknow

인생은 Byte와 Double 사이 Char다. 아무말이나 해봤습니다.