jiho_bae
Go devlog
jiho_bae
전체 방문자
오늘
어제
  • 분류 전체보기 (158)
    • JavaScript (38)
      • theory (34)
      • vanilla (4)
    • HTML & CSS (2)
    • Browser (3)
    • CS (6)
      • linux (1)
      • shell (2)
      • compiler (2)
    • DS & Algorithm (87)
      • theory (5)
      • basic (7)
      • programmers (30)
      • baekjoon (45)
    • Design Pattern (2)
    • Error (4)
    • Git & Github (4)
    • Tools (1)
    • 부트캠프 (4)
    • Small Tips (2)
    • Java (3)
    • test (1)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • 자바스크립트 배열의 특수함
  • 외벽 점검 javascript
  • safari invalid date error
  • 가사 검색 자바스크립트
  • 13460 javascript nodejs
  • 억억단을 외우자 javascript
  • 카카오 코딩테스트 양궁대회 nodeJS
  • 리코쳇 로봇 javascript
  • 자바스크립트 채팅방 스크롤
  • 대충만든자판 javascript
  • 자바스크립트 이벤트 위임
  • 자바스크립트 모듈 시스템
  • 백준 자바스크립트 입력 템플릿
  • 퀵정렬 자바스크립트
  • 25632 소수 부르기 게임
  • 백준 17406 nodeJS
  • 깃 이전 커밋에서 새 브랜치 만들기
  • 병합정렬 자바스크립트
  • 프로그래머스 숫자카드나누기 javascript
  • 자바스크립트 커링
  • 1753 최단경로 javascript
  • safari Date format NaN
  • 덧칠하기 javascript
  • 계수정렬 자바스크립트
  • 리액트 프로젝트 디버깅하기
  • JavaScript
  • fetch 취소하기
  • javascript use strict
  • 자바스크립트 비동기 마이크로 태스크 큐와 렌더링 과정
  • 자바스크립트 sort는 왜 그모양일까

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
jiho_bae

Go devlog

[함수형] 커링 Currying을 배워보자.
JavaScript/theory

[함수형] 커링 Currying을 배워보자.

2022. 6. 1. 18:39

함수형 시리즈

 

[함수형] 클로저 Closure에 대해 알아보자.

클로저 클로저란, 내부 함수가 함수가 참조하고 있는 주변 환경에 접근할 수 있는 것을 의미한다. MDN에서는, 클로저는 독립적인 (자유) 변수를 가리키는 함수이다. 클로저 안에 정의된 함수는 만

gobae.tistory.com

이전 클로저 포스팅에 이어 이번에는 커링이다.

 

 


커링?

사진 속 연산을 이해할 수 있는가?
이해할 수 있다면 이 포스팅은 스킵하면 된다.

 

 

커링(Currying)은 함수형 프로그래밍에서 등장하는 필수 개념이다.

 

쉽게 말하면, '함수를 반환하는 함수'이다.

 

커링이 왜 사용될까?

  • 함수의 재활용을 위해서
    • 원하는 함수들을 조합해서 사용할 수 있다.
  • 하나 이상의 인수의 함수를, 하나의 인수를 받는 함수로 축소할 수 있다.
    • 그래서 더 가벼운 함수 제작이 가능하다.

 

그럼 함수의 재활용이란 무엇일까?

    function add(a,b){
        return a+b;
    }

 

다음 add 함수를 재활용 하려면?

    function addTwo(a){
        return add(a, 2);
    }

이렇게 2 + @를 해주는 addTwo 함수를 만들 수 있다.

 

만약 add3, add4, add5 ... 등의 여러 함수가 필요하다고 하자.

    function addTwo(a){
        return add(a, 2);
    }
    function addThree(a){
        return add(a, 3);
    }
    function addFour(a){
        return add(a, 4);
    }

분명 add 함수를 재활용하긴 하지만, 뭔가 이상하다.


여기에 커링을 적용해보자.

    function addX(x){
      return function(a){
        return add(a, x);
      }
    }

    const addTwo = addX(2);
    const addThree = addX(3);
    const addFour = addX(4);

    addTwo(2) // 2+2 = 4
    addThree(5) // 3+5 = 8
    addFour(1) // 4+1 = 5

다음과 같이 addX 함수를 이용해서 여러 파생 함수들을 만들 수 있다.

 

addX 함수는 이렇게 동작한다.

  • 인자 x를 받아서 익명함수를 반환한다. 그 함수는 function(a){return add(a,x);} 형태이다.
  • 반환받은 값인 함수는 인자 a를 요구한다. a를 넣어주면 add(a,x)의 실행 결과를 반환한다.

이처럼 함수 실행을 위한 인자를 한번에 받지 않고, 여러 차례에 나눠서 받을 수 있다.

 

이 예시를 화살표 함수로 나타내면,

    function addX(x){
      return function(a){
        return add(a, x);
      }
    }

    const addX = x => a => add(a,x);

이렇게 더 간단해진다.


함수를 인자로 받는 커링함수 만들어보기.

자바스크립트에서는 함수도 값이다. 


그러므로 함수의 인자로 또 다른 함수도 받을 수 있다.

    function curry(fn){
      return function(a){
        return function(b){
          return fn(a,b);
        }
      }
    }

이제 이 함수를 어떻게 써야할지가 대충 보일 것인데,
정확히 위에서 선언했던 addX와 동일하게도 만들 수 있다.

 

    function add(a,b){
      return a+b;
    }

    const addX = curry(add);
    const addTwo = addX(2);
    console.log(addTwo(5)) // 5+2 = 7

함수 자체를 인자로 받아서 활용할 수 있는 것을 알게 되면, 코드를 작성하는 스타일이 더 다양해진다.

이제는 글 맨 앞에서 다뤘던 괴상한 화살표함수의 모습에 대해서 왜 동작하는지를 이해할 수 있다.

 

    const curry = fn => fn2 => a => b => fn(a,b)+fn2(a,b)

    // 이 함수를 뜯어보면 다음과 같다.

    function curry(fn){
      return function(fn2){
        return function(a){
          return function(b){
            return fn(a,b) + fn2(a,b);
          }
        }
      }
    }

 

add, multiply 함수를 차례대로 생성해서 방정식을 만들어보자.

    function add(a,b){
      return a+b;
    }

    function multiply(a,b){
      return a*b;
    }

    const fnIsAdd = curry(add);
    const fnIsAddFn2IsMultiply = fnIsAdd(multiply);
    const fnIsAddFn2IsMultiplyAis3 = fnIsAddFn2IsMultiply(3);
    const add3and5Plusmultiply3and5 = fnIsAddFn2IsMultiplyAis3(5);
    console.log(add3and5Plusmultiply3and5) // (3+5) + (3*5) = 8+15 = 23

    const oneline = curry(add)(multiply)(3)(5);
    console.log(oneline) // (3+5) + (3*5) = 8+15 = 23

처음에는 각각의 절차를 나타내봤고, 한번에 작성한 online 변수를 작성해봤다.


커링 응용하기

마지막으로 커링의 가벼운 응용을 보고 마칠 예정이다.

 

방금 인자로 함수도 받을 수 있다는 것을 알았다.
그렇다면 정말 '다양한 함수들을 조합'하는 길이 열린 셈이다.

 

이제 조금 더 간결하게 function 키워드 없이 화살표 함수로 커링함수를 표현하겠다.

방정식 4x * (x+2)을 수행할 함수를 만들어보자.

    const add = (a,b) => a+b;
    const multiply = (a,b) => a*b;

    const addX = x => a => add(a, x);
    const addTwo = addX(2);

    const multiplyX = x => a => multiply(a, x);
    const multiplyFour = multiplyX(4);

이렇게 커링을 이용해 addTwo, multiplyFour 함수를 만들었다.

 

    const compose = fn => fn2 => x => fn2(x) * fn(x);
    const equation = compose(addTwo)(multiplyFour);
    equation(10) // (4 * 10) * (10 + 2) = 40 * 12 = 480

equation 함수에 넣는 값이 x가 되어 4x(x+2)의 다양한 값에 대한 결과를 받을 수 있다.

 

만약 추가적인 요구사항이 생겨서, 5x(x+2)의 결과를 반환하는 함수가 필요하다면?

    const multiplyFive = multiplyX(5);
    const equaion2 = compose(addTwo)(multiplyFive);
    equation2(10) // (5 * 10) * (10 + 2) = 600

이렇게 표현할 수 있다.


마지막으로 위에서 선언한 equation 함수를 생성하면서 중복되는 부분을 제거하면,

    const addTwo = addX(2);
    const addFour = addX(4);
    const multiplyFour = multiplyX(4);
    const multiplyFive = multiplyX(5);

    const compose = fn => fn2 => x => fn2(x) * fn(x);
    const composeAddTwo = compose(addTwo);

    const equation1 = composeAddTwo(multiplyFour); // 4x(x+2)
    const equation2 = composeAddTwo(multiplyFive); // 5x(x+2)
    const equation3 = composeAddTwo(addFour) // (x+4)(x+2)

위와 같이 인자로 받은 함수들을 교체해주면서, 유사한 함수들을 여러개 만들 수 있다.

 

아주 간단한 예시들을 통해 여러 함수들을 유용하게 조합할 수 있는 커링을 살펴보았다.

 

커링을 통한 함수 합성은 어려워지려면 한도 끝도 없이 어려워 질 수 있기 때문에...

함수형 프로그래밍을 프로젝트에 적용하면서 함수 조합 및 합성을 고려해보면 커링에 대해 진하게 느끼지 않을까 싶다.

(사실 빡세게 머리를 굴려도 간단한 재활용 함수들을 만들기조차 힘들더라..ㅎㅎ)

 

 

 

저작자표시 (새창열림)

'JavaScript > theory' 카테고리의 다른 글

엄격모드. "use strict"  (0) 2022.07.20
이벤트 위임, 버블링, 캡쳐링 (Event Delegation, bubbling, capturing)  (0) 2022.07.11
[자바스크립트] 마이크로 태스크 큐의 비동기 작업 처리와 렌더링 시점을 알아보자.  (1) 2022.04.14
브라우저/노드 환경에서 모듈, AMD, CommonJS, UMD 알아보기  (1) 2022.02.15
자바스크립트의 this는 어떻게 결정되는가?  (0) 2022.01.25
    'JavaScript/theory' 카테고리의 다른 글
    • 엄격모드. "use strict"
    • 이벤트 위임, 버블링, 캡쳐링 (Event Delegation, bubbling, capturing)
    • [자바스크립트] 마이크로 태스크 큐의 비동기 작업 처리와 렌더링 시점을 알아보자.
    • 브라우저/노드 환경에서 모듈, AMD, CommonJS, UMD 알아보기
    jiho_bae
    jiho_bae
    하루에 한 걸음씩

    티스토리툴바