티스토리 뷰

🙋‍♀️ 기술면접 대비

Currying과 Composition

2023. 2. 15. 12:50

Currying과 Composition 모두 함수형 프로그래밍의 핵심들이다.

 

 

Currying

-  f(a, b, c)처럼 단일 호출로 처리하는 함수를 f(a)(b)(c)와 같이 각각의 인수가 호출 가능한 프로세스로 호출된 후 병합되도록 변환하는 것

-  currying은 함수를 호출하지 않는다. 변환한다.

-  함수의 재사용성을 높이기 위해 사용된다.

const order = store => menu => 
	console.log(`${store}에서 ${menu}를 주문`)
    
    
// 호출
order('카페')('아메리카노');
order('카페')('라떼');

위 함수를 ES5로 바꾸면 아래와 같다.

function order(store) {
    return function (menu) {
        console.log(`${store}에서 ${menu}를 주문`)
    } 
}

내부 function에서 store에 접근할 수 없음 -> 가능하게 해주는게 클로저

const cafe = order('카페');

cafe의 타입은 함수

 

위 코드에서 중복을 없애서 아래처럼 작성할 수 있다.

cafe('아메리카노');
cafe('라떼');

 

위와 같은 패턴은 자바스크립트로 게임을 만들 때 많이 사용된다.  (설치형  →  업데이트하기 전엔 변화가 없음)

또는, 앱을 만들거나 오프라인으로 실행되게 하겠다했을 때

 

 

커링 추가 예제 

function yourPhoneNumber(start, number) {
    console.log(start + number);
}

const phoneNumber = start => number => yourPhoneNumber(start, number);
const phoneNumber010 = phoneNumber('010');

phoneNumber010(12345678);    // 01012345678



// 예제 출처
// https://itprogramming119.tistory.com/entry/Javascript-%EC%BB%A4%EB%A7%81Currying-%ED%95%A8%EC%88%98%EB%9E%80

 

 

 

 

 

 

 

Composition

아래와 같이 3개의 함수가 있고 f2는 f1의 결과를 받고, f3은 f2의 결과를 받는다고 가정했을 때

f1 : fullName      // 풀네임으로 바꾸는 함수
f2 : appendAddr    // 주소를 추가하는 함수
f3 : removeNames    // firstName, lastName은 지우는 함수 (fullName만 필요한 경우)

 

위 세 가지 동작을 userDeatil이라는 함수 안에  다 작성한다면 명령형 프로그래밍이 된다.

(하나하나가 선언형이라도 그게 모여서 명령형이 되는 것)

function userDetail (user) {
    // ... 풀네임되고
    // ... 주소 추가하고
    // ... 이름, 성 삭제하고
}

💡  명령형(절차적), 선언형 프로그래밍

https://ui.dev/imperative-vs-declarative-programming

https://dev.to/ruizb/declarative-vs-imperative-4a7l

 

 

 

위 userDetail 함수의 내용들을 분리하여 순차적으로 실행되도록 

const fullName = (user) => ({ ...user, fullName: `${user.firstName} ${user.lastName}` });
const appendAddr = (user) => ({ ...user, addr: 'Seoul' });
const removeNames = (user) => {
    delete user.firstName;
    delete user.lastName;
    return user;
}

const compose = (...fns) => (obj) => fns.reduce(
    (c, fn) => fn(c), 
    obj
);

const data = compose(
    fullName, 
    appendAddr, 
    removeNames,
)(user);

위 compose코드를 ES5로 reduce도 사용하지 않고 작성하면

function compose() {
    var fns = arguments;
   
    return function rfn(obj, idx) {
        idx = idx || 0;
        if(idx < fns.length) {
             return rfn(fns[idx](obj), idx+1);
        }
        return obj;
    }
}

만약 compose()에 아무 함수도 들어오지 않는다면 (=  compose()(user) 라면)

arguments는 {}이고 ([], undefined, null 아님)

리턴값은 user가 그대로 나온다. (아무 함수도 실행되지 않았으니까)

 

 

 

 

 

 

 

참고 자료

🔗 [시니어코딩]  React 이론 4강 - 함수형 프로그래밍의 백미, Currying과 Composition

🔗 [MDN]  Array.prototype.reduce() - 함수 구성을 위한 파이프 함수

🔗 Curry and Function Composition

🔗 [javascript.info]  커링

🔗 [freeCodeCamp]  How to Use Currying and Composition in JavaScript

반응형

'🙋‍♀️ 기술면접 대비' 카테고리의 다른 글

CORS  (0) 2023.01.18
CSR, SSR, SSG, ISR  (0) 2022.09.27
브라우저 렌더링 과정  (0) 2022.09.26
프로필사진
개발자 삐롱히

프론트엔드 개발자 삐롱히의 개발 & 공부 기록 블로그