함수형 프로그래밍은 외부 상태를 갖지 않는 함수들의 연속으로 프로그래밍을 하는 패러다임
여기서 함수는 "Input을 통해 Output을 만들어내는 일련의 코드 묶음"이라 표현할 수 있다.
함수형 프로그래밍은 이 함수들 위주로 구성된 프로그래밍 기법인데 여기서 중요한 것은 함수는 순수함수이자 1급함수여야 한다.
순수 함수는 외부 상태를 갖고 있지 않은 함수로 외부 상태는 Input, 즉 파라미터로 받아온 데이터 외에 함수 밖에서 정의된 데이터를 사용하지 않는다는 뜻이다.
예시
// 잘못된 예
int c = 1;
public int firstFunction(int a, int b){
return a + b + c;
}
// 올라른 예
public int firstFunction(int a, int b){
return a + b;
}
1급 함수는 아래의 조건을 충족시키는 함수를 뜻한다.
1. 함수/메서드의 매개변수로 전달될 수 있는가
2. 함수/메서드의 반환값으로 사용될 수 있는가
3. 변수에 할당 가능한가
즉 쉽게 말해 함수를 오브젝트로 다룰 수 있는가 여부에 따라 1급 함수로 구분한다.
객체지향 프로그래밍은 명령형 프로그래밍으로 추상화한 객체에게 행동을 위임하는 방식의 프로그래밍 기법입니다.
따라서 프로그래머는 객체 단위로 구현을 하며 위임 받은 행동을 어떻게 구현해야할 지 집중합니다.
함수형 프로그래밍은 선언형 프로그래밍으로 행동을 추상화하여 넘겨받은 데이터를 처리하는 방식의 프로그래밍 기법입니다.
따라서 프로그래머는 함수 단위로 구현을 하며 무슨 행동을 해야하는가에 집중합니다.
OOP와 FP의 차이는 추상화 단위라고 생각한다. OOP는 명사, 또는 동작의 주체를 추상화 시키고 FP는 동사, 동작 그 자체를 추상화 시킵니다.
예를 들어 아래의 로직을 구현한다고 하면 다음과 같이 볼 수 있습니다.
- 사자가 고기를 먹습니다.
- 사람이 밥을 먹습니다.
- 기린이 풀을 먹습니다.
OOP에서는 사자, 사람, 기린을 추상화 시켜 동물이라는 객체를 만든 후, 이를 상속받아 각각 사자, 사람, 기린을 구현한 후, 내부에서 먹는다라는 행위를 어떻게 구현할 것인지 고민합니다.
public interface Animal {
void eat(String meal);
}
class Lion implements Animal{
@Override
public void eat(String meal) {
System.out.println(meal + "를 먹습니다.");
}
}
class Human implements Animal{
@Override
public void eat(String meal) {
System.out.println(meal + "를 먹습니다.");
}
}
class Giraffe implements Animal{
@Override
public void eat(String meal) {
System.out.println(meal + "를 먹습니다.");
}
}
FP에서는 무슨을 해야하는가, 즉 먹는다 라는 행위를 추상화시켜 구현하여 파라미터로 데이터를 받아와서 실행합니다.
public class Eat {
public static void main(String[] args){
BiFunction<String, String, String> eat = (x, y) -> {
String result = x + "가 " + y + "를 먹습니다.";
System.out.println(result);
return result;
};
String lion = eat.apply("사자", "고기");
String human = eat.apply("사람", "밥");
String giraffe = eat.apply("기린", "풀");
}
}
함수형 프로그래밍을 정리하면 결국 함수 단위로 추상화하여 구현한다는 것이다. 그렇다면 왜 그렇게 하는 것인가??
최근 대용량 데이터를 처리하기 위해서 병렬 프로그래밍이 중요해지고 있다. 이 병렬 프로그래밍에서 중요한 것은 아래와 같다
1. 입력값이 같다면 항상 같은 결과를 도출해야한다.(사이드 이펙트가 없다)
2. 디버깅을 위해 코드가 간결해야한다.
객체 지향 프로그래밍에서는 위 조건을 충족시키는 코드 짜기가 어렵다. 객체의 멤버 변수가 변경되면 입력값이 같더라도 다른 결과를 도출하고 객체간의 상호 작용을 위해 서로 의존성을 갖게되어 프로그램 복잡도가 증가되어 디버깅이 어렵다.
반면 함수형 프로그래밍은 순수 함수를 다루기 때문에 입력값이 같다면 항상 같은 값을 반환하며 함수 조합으로 구현되기 때문에 코드가 간결해집니다.
따라서 함수형 프로그래밍은 사이드 이펙트가 없고 코드가 간결해져 디버깅이 용이하기 때문에 병렬 프로그래밍에 적합하여 최근에 자주 사용됩니다.