[ODOP:01]Java 함수형 프로그래밍 - 01. 함수형 프로그래밍 소개
벤 바이디히 의 'A Functional Approach to Java' 를 읽고 정리 한 내용입니다 이 포스트 에서는 함수형 프로그래밍의 특징과 장단점을 다룹니다
01.함수형_프로그래밍_소개
자바의 함수형 프로그래밍 방식인 람다는 람다 대수(Lambda calculus)
에 뿌리를 두고 있다
람다 대수의 구성요소
- 추상화 (Abstraction) : 단일 입력을 받는 익명 함수. 람다를 의미
- 응용 (Application) : 값에 추상화 적용되어 결과 생성. 함수나 메서드의 호출을 의미함.
- 베타 축약 (B-reduction) : 추상화 된 변수를 대입 된 인수로 대체
함수형 프로그래밍 개념
함수형 프로그래밍은 추상 함수에 기반을 두고, '무엇을 해결 할 것인가' 에 초점을 맞추고 있다
순수 함수
- 동일한 입력에 대해 항상 동일한 출력을 반환한다
- 어떠한 사이드 이펙트 없이 자기 충족적 성질을 가진다
위 두 가지 조건 중 하나라도 위반하면 불순 함수로 간주 한다
(단, 그렇다고 해서 불순함수가 기능적으로 우수하다는 말은 아니다)
순수 함수가 가지는 장점은, 다른 프로그램을 작성 할 때도 언제나 일관적인 응답을 통해
코드의 유지보수성이 좋아진다는 것이다.
불변성
자바의 Entity 라는 개념은 언제나 Mutable 하다.
이러한 변경 가능한 객체는 비즈니스의 이해나 병렬 문제, 내부 함수의 일관성이 깨지는 문제 등이 있을 수 있다
재귀
함수의 재귀적인 호출은 스택오버플로의 위험성을 갖는다
많은 함수형 언어 에서는 이러한 문제를 해결하기 위해 꼬리물기 최적화(Tail call optimization)
또는루프 언롤링(Loop unrolling)
과 같은 최적화 기법을 활용한다
일급 함수
함수 자체를 객체로 취급하여 아래의 항목을 만족 할 수 있게 하는 것이다
- 함수 자체를 다른 함수에 인수로 전달이 가능하다
- 함수 자체를 반환 값으로 사용 가능하다
- 함수 자체를 변수에 할당 가능하다
고차 함수
일급 함수의 특성을 가지는 함수들을 바탕으로 사용할 수 있는 기법
- 함수를 인수로 받거나
- 반환하거나
- 합수 합성을 가능하게 한다
함수 합성
순수 함수를 결합 하여 더욱 복잡한 표현식을 만들어내는 방법
각각의 함수들을 작은 단위로 명확하게 만들고, 재사용이 쉽도록 한다
필요에 따라 빠르게 조합하여 사용 할 수 있다
커링 (Currying)
커링은 여러 개의 인수를 받는 함수를 각 인수를 하나씩만 받는 여러 함수의 체인으로 변환하는 기법이다
예를 들어, 세 개의 인수를 받는 함수가 있다고 가정해 보자
원래 함수:
int payment(int a, int b, int c);
커링을 적용한 경우, 함수는 다음과 같이 변환 된다.
Function<Integer, Function<Integer, Function<Integer, Integer>>> payment = a -> b -> c -> ...;
커링을 사용하면 함수 호출은 다음과 같이 나열된다
int x = payment.apply(a).apply(b).apply(c);
부분 적용 함수 애플리케이션 (Partial Function Application)
부분 적용 함수는 기존 함수의 인수 중 일부만을 고정시켜 새로운 함수를 생성하는 과정이다
이 방식은 커링과 비슷해 보일 수 있지만, 모든 인수를 단계적으로 적용하지 않고 일부 인수만 미리 적용하는 것이 특징이다
예를 들어, 세 개의 인수를 받는 payment 함수가 있고, 첫 번째 인수 a만을 미리 적용하여 새로운 함수를 생성할 수 있다
원래 함수
int payment(int a, int b, int c);
부분 적용을 적용한 경우
BiFunction<Integer, Integer, Integer> paymentWithA = (b, c) -> payment(a, b, c);
그런 다음, 이 부분 적용 함수를 사용할 수 있다
int x = paymentWithA.apply(b, c);
느긋한 계산법(Lazy evaluation)
표현식의 계산 결과가 실제 필요한 시점까지 계산하지 않는 기법
런타임 중에 실제 필요한 분기와 반복만을 계산할 수 있다는 장점이 있다
하지만 연산의 정확한 시기를 예측 할 수 없기 때문에 성능에 악영향이 있을 수 있다.
자바에서는 특정 도구를 활용하여 느긋한 계산법을 적용 할 수 있다
함수형 프로그래밍의 장점
- 간결성 (Simplicity)가변 상태에서 사이드 이펙트가 없는 경우 함수는 더 작아지고 가장 적은 단위의 일만을 수행 한다
- 일관성 (Consistency)불변 자료구조는 신뢰성과 일관성을 지킨다.걱정하지 않아도 된다
- 예상하지 못하거나
- 의도하지 않았으며
- 동시성 문제에서도
- 수학적 정확성 (Mathematical correctness)코드가 순수 할 수록 논리적 추론이 쉬워진다
- 안전한 동시성 (Safer concurrency)자바에서 제대로 처리하기 가장 어려운 작업 중 하나함수형 개념을 활용하여 안전한 병렬 처리의 이점을 누릴 수 있다
- 모듈성 (Modularity)작고 독립적인 함수는 간단한 재사용성과 모듈성을 제공한다
- 테스트 용이성 (Testability)순수 함수, 참조 투명성, 불변성, 역할 분리와 같은 많은 함수형 개념은 테스트와 검증을 더 쉽게 만든다.
함수형 프로그래밍의 단점
- 고수준의 추상화 (Higher level of abstraction)OOP 에서는 객체를 사용하여 추상화를 모델링 하는 반면, 함수형은 더 높은 수준을 사용하여 자료구조를 표현한다.그만큼 우아할 수 있지만, 종종 이해하기 어려워진다
- 상태 처리 (Dealing with state)많은 패러다임에서 상태 처리는 어려운 문제이다. FP(함수형 프로그래밍) 방식 에서는 불변성을 이용하여 많은 버그 발생 가능성을 제거 하지만객체지향의 setter 를 사용하던 것과 비교하면 더 어렵게 느껴질 수 있다
- 성능 영향도(Performance implication)FP 는 동시성 환경에서 사용하기 더 쉽고 안전하다. 이는 다른 패러다임과 비교했을 때 반드시 빠르다는 것은 아니다.불변성이나 재귀와 같은 많은 함수형 기술은 오버헤드로 인해 성능이 저하될 수 있다.
- 최적의 문제 상황(Optimal problem context)모든 문제 상황이 함수형 접근에 적합한것은 아니다.위와 같은 도메인은 함수형과 어울리지 않을 수 있다.데이터 지역성, 명시적 메모리 관리 같은 민감한 사항들이 함수형과 어울리지 않는 원인이 된다.
- I/O
- 컴퓨팅 파워
- 임베디드 컨트롤
- 저수준 시스템