함수형 프로그래밍은 자료처리를 순수 함수로 처리하고, side-effect를 제거하는 프로그래밍 패러다임입니다. 그렇다면, 왜 이러한 패러다임이 조명받고 있을까요?
하드웨어의 성능이 발전하면서, 멀티 스레딩 기술은 보편화 되었습니다. 하지만, 이에 따라 여러 개의 스레드가 공유 자원에 동시에 접근하면서, 프로그램의 실행 결과가 예측 불가능해지는 문제가 발생했습니다.
아래의 예시 코드를 보면, 두 개의 스레드가 shared 변수에 동시에 접근하여 값을 변경하고 있습니다. 각 스레드의 실행 시점과 순서를 예측할 수 없기 때문에, 상황에 따라 shared의 값이 0, 100, 200, 300 등 다양하게 출력될 수 있습니다. 이를 컴퓨터 과학에서는 side-effect라고 합니다.
var shared = 0
Thread1 {
shared += 100
}
Thread2 {
shared += 200
}
print(shared)
/*
결과 값 --------------------------------------------
- 0: 두 스레드가 모두 실행되기 전에 print문이 실행된 경우
- 100: Thread1만 실행된 후 print문이 실행된 경우
- 200: Thread2만 실행된 후 print문이 실행된 경우
- 300: 두 스레드가 완전히 실행된 후 print문이 실행된 경우
*/
side-effect를 해결하는 가장 간단한 방법은 데이터를 변경하지 않으면 됩니다. 기존 데이터를 변경하지 않으며, 필요 시 기존 데이터를 활용해 새로운 데이터를 만들어 내는 것입니다.
FP는 이를 수행할 수 있는 가장 훌륭한 대안입니다.
Pure-Function(순수 함수)란 동일한 input에 대해서 동일한 output을 가지는 함수를 말합니다. 아래의 예시처럼 Pure-Function은 output을 생성하는데 오직 input(파라미터)만을 사용합니다.
// Pure-Function
func pure(_ input: Int) -> Int {
return input * 3
}
// None Pure-Function
var value: Int = 3
func nonePure() -> Int {
return value * 3 // 함수 외부 변수 사용
}
함수를 파라미터로 받거나, 리턴하는 함수를 High-Order Function(고차 함수)라고 합니다. 이를 좀 더 전문적인 용어로 ‘함수를 1급 객체로 활용한다’라고 할 수 있습니다. 대표적으로, Foundation에서 제공하는 map(), filter() 등이 있습니다.
*1급 객체: 1)변수에 저장될 수 있으며, 2)함수의 파라미터로 전달되거나 3)리턴값으로 사용될 수 있는 객체