함수형 프로그래밍이란 순수 함수와 선언형 프로그래밍을 기반으로 함수 조합 및 모나드 조합으로 코드를 설계, 구현하는 기법입니다.
순수 함수 : https://darrengwon.tistory.com/595?category=905593
선언형 프로그래밍 : https://darrengwon.tistory.com/761?category=905593
함수형 프로그래밍 언어는 정적 타입, 자동 메모리 관리, 계산법, 타입 추론, 일등 함수를 기반으로 대수 데이터 타입, 패턴 매칭, 모나드, 고차 타입 등의 기능을 제공합니다. 그러나 함수형 프로그래밍의 속성을 구현하기 위한 기능을 모든 프로그래밍 언어가 지원하는 것도 아니고, 대부분은 절차형 프로그래밍과 함수형 프로그래밍을 섞어 쓰게 됩니다.
제네릭 함수
TS에서 함수 조합을 하기 위해서는 어떤 타입에도 대응하도록 타입을 지정해야 하므로 제네릭을 사용해야 합니다.
function test<T>(arg: T): void {
console.log(arg);
}
function doubleGeneric<T, Q>(arg1: T, arg2: Q): void {
console.log(arg1, arg2);
}
// 타입에 연연하지 않고 사용할 수 있음
test("hello");
test(3);
test(true);
test({ name: "da", age: 23 });
doubleGeneric("hello", 3);
doubleGeneric(true, { name: "da", age: 23 });
고차 함수 (high order function)
전에 고차 컴포넌트와 함께 고차 함수의 개념을 다룬 적이 있습니다.
https://darrengwon.tistory.com/756?category=867626
수학적으로 쉽게 설명하면 합성 함수입니다. 함수의 결과값이 다른 함수의 매개변수로 들어갈 수 있다는 간단한 아이디어입니다.
x ~> f ~> g ~> h ~> y
y = h(g(f(x)))
다음과 같이 커링으로 사용할 수 있습니다.
커링 : https://darrengwon.tistory.com/738?category=905593
type FirstOrderFunc<T, R> = (T) => R;
type SecondOrderFunc<T, R> = (T) => FirstOrderFunc<T, R>;
type ThridOrderFunc<T, R> = (T) => SecondOrderFunc<T, R>;
const inc: FirstOrderFunc<number, number> = (x) => x + 1;
const add: SecondOrderFunc<number, number> = (x) => (y) => x + y;
const add3: ThridOrderFunc<number, number> = (x) => (y) => (z) => x + y + z;
console.log(inc(1));
console.log(add(3)(4));
console.log(add3(1)(2)(3));
고차 함수를 호출 연산자 모두 쓸 필요 없이 덜 사용해서 부분 적용 함수를 사용할 수도 있습니다.
const partialFunc = add3(1)(2);
console.log(partialFunc(3));
클로저
과거 https://darrengwon.tistory.com/633 에 정리한 바에 따르면 클로저는 외부 함수가 사라졌음에도 내부 함수가 외부 함수에서 정의한 변수를 사용할 수 있다는 것입니다. 이를 '지속되는 유효 범위'(persistence scope)라고 합니다.
function add(x) {
// 내부 함수에서 외부 함수의 x에 접근할 수 있습니다.
return function add2(y) {
return x + y;
};
}
console.log(add(2)(3));
함수 조합
작은 함수를 조합하여 하나의 기능을 하는 또 다른 함수를 조합해내는 것을 말합니다. compose와 pipe라는 이름의 메서드가 관습적으로 사용됩니다. compose(f, g, h)는 f(g(h(x))) 순서지만 pipe(f, g, h)는 h(g(f(x))) 순서로 실행합니다.
함수를 합치는 compose 함수를 작성해보았습니다. (ramda 등 다른 FP 패키지를 통해 compose를 할 수 있습니다만 연습하는 느낌으로 구현해봅시다)
const compose = (...functions: readonly Function[]) => (x) => {
const deepCopiedFunctions = [...functions];
return deepCopiedFunctions.reverse().reduce((value, func) => func(value), x);
};
const inc = (x) => x + 1;
const composedAdd = compose(inc, inc, inc);
// inc(inc(inc(1)))
console.log(composedAdd(1)); // 4
참고한 글, 좋은 글)
'Programming paradigm > 🧱 functional JS' 카테고리의 다른 글
Lazy Evaluation(지연 평가)와 지연성 map, filter (0) | 2021.05.24 |
---|---|
Array.prototype.[method]보다 다형성 높은 map, filter, reduce (0) | 2021.05.23 |
FP을 위한 선언형 프로그래밍(declarative) (0) | 2020.08.25 |
JS 함수형 프로그래밍을 위한 사전 지식 : 순수함수, 일급함수, 커링 (0) | 2020.07.05 |