함수 로 함수 만들 기 2 커 링 
 2017 년 04 월 17 일 분류 : JS 태그 : # javascript , # functional - programming , # curry 
 이전 글 : ( 함수 형 JS ) 함수 로 함수 만들 기 1 다형 성 
 왜 커 링 을 사용 하 는가 ? 
 이 글 에서 는 함수 로 함수 만들 기 두 번 째 시간 으로 커 링 ( currying ) 에 대해 알아보 겠 다 . 커 링 이 란 다중 인자 를 받 는 함수 를 단일 인자 함수열 로 만드 는 것 을 말 한다 ( 커 링 - 위키백과 , 우리 모두 의 백과사전 ) . 
 커 링 의 정의 에 대해서 는 잠시 잊 어 버려 도 좋 다 . 먼저 문자열 을 숫자 로 바꾸 는 parseInt 사용법 에 대해 눈 을 돌려 보 자 . 아래 코드 의 결과 를 예측 할 수 있 겠 는가 ? 
 정수 로 이뤄진 배열 [ 11 , 11 , 11 , 11 ] 을 기대 하 는 코드 라고 미루 어 짐작 할 수 있 다 . 그러나 결과 는 그렇 지 않 다 . [ 11 , NaN , 3 , 4 ] 라는 값 이 나온다 . 왜 그럴까 ? 
 원인 을 이해 하 려면 parseInt 함수 의 인터페이스 부터 살펴봐야 한다 . parseInt 는 parseInt ( string , radix ) 형태 로 사용 된다 . 변환 한 정수 문자열 string 과 진수 를 나타내 는 radix 변수 를 인자 로 받 는데 2 와 36 범위 로 한정 한다 . ( [ parseInt ( ) ( https : / / developer . mozilla . org / ko / docs / Web / JavaScript / Reference / Global _ Objects / parseInt ) ) 
 한편 맵 함수 는 전달 인 자 로 콜백 함수 를 넣 을 수 있 다 . 콜백 함수 는 function callback ( currentValue , index , array ) 형태 로 사용 한다 . 배열 요소 중 현재 처리 되 고 있 는 값 을 currentValue 로 받 고 인덱스 와 해당 배열 이 뒤따라 온다 . ( Array . prototype . map ( ) ) 
 위 코드 에서 는 맵 함수 의 콜백 함수 로 parseInt 를 넘겨 주 었 다 . 따라서 parseInt 의 파라 매터 는 string 에 currentValue 가 오 고 radix 에 index 가 온다 . parseInt 의 두 번 째 파라 매터 인 진수 값 을 배열 요소 의 인덱스 값 0 , 1 , 2 , 3 을 전달 했 기 때문 에 함수 는 아래 순서 대로 호출 될 것 이 다 . 
 parseInt 의 두 번 재 파라 매터 에 진수 값 을 잘못 전달 한 탓 이 다 . 원래 의도 는 parseInt 에 문자열 만 전달 하 고 두 번 째 파라 매터 는 생략 해서 10 진법 결과 를 얻 으려는 의도 였을 것 이 다 ( parseInt 의 radix 파라 매터 는 기본 값 이 10 이 다 ) . 그렇 다면 이 문제 는 parseInt 함수 에 첫 번 째 문자열 파라 매터 만 넘겨 주 도록 하 는 방법 으로 로 해결 할 수 있 을 것 이 다 . 
 여기 서 커 링 의 필요 성 이 등장 한다 . 서두 에 언급 한 커 링 의 정의 를 떠올려 보 자 . 다중 인자 를 받 는 함수 를 단일 인 자 만 받 는 함수열 로 변경 하 는 것 이 커 링이다 . 2 개 인자 를 받 는 parseInt 함수 를 1 개 인자 만 받 도록 고정 하 는 것 이 커 링 인 셈 이 다 . 
 parseInt 를 커 링 하 기 위한 커리 함수 를 만들 겠 다 . 함수 fun 을 인자 로 받 고 , arg 를 인자 로 받 는 함수 를 반환 한다 . 반환 된 함수 를 실행 하 면 클로 져 로 캡쳐 된 fun 에 인자 로 받 은 arg 를 전달 하 여 실행 하 고 그 결과 를 반환 한다 . 
 curry ( parseInt ) 는 두 개 의 인자 를 받 는 parseInt 함수 를 하나 의 인자 만 받 도록 강제 하 는 함수 를 반환 한다 . curry ( parseInt ) ( ' 11 ', 2 ) 처럼 두 개 인자 를 넘겨 주 더라도 첫 번 재 파마 매터 인 문장 려 ‘ 11 ’ 만 parseInt 에 전달 된다 . 나머지 파라 매터 인 정수 2 는 무시 된다 . 
 전달 인 자 1 개 로 고정 시킨 , 즉 커 링 된 함수 를 맵 함수 의 콜백 함수 로써 전달 하 면 우리 가 원래 의도 한 결과 를 얻 을 수 있 다 . 이 함수 는 map 함수 가 전달 한 배열 의 인덱스 값 인 두 번 째 파라 매터 는 무시 하 고 첫 번 째 파라 매터 인 배열 요소 값 만 사용 해서 parseInt 를 호출 하 기 때문 이 다 . 
 curry 2 ( ) 
 문자열 을 10 진수 로 만들 기 위해 parseInt 가 하나 의 파라 매터 만 전달 받 도록 커 링 을 사용 했 다 . parseInt 의 radix 파라 매터 는 없 을 경우 기본 값 10 을 사용 한다 . 이진수 값 을 얻 으려면 parseInt 의 radix 에 2 를 넘겨 줘야 한다 . 어떻게 하 면 커 링 으로 이 문제 를 풀 수 있 을까 ? 
 curry ( ) 함수 가 한 개 의 파라 매터 를 고정 한 것 은 반환 한 함수 가 한 개 의 파라 매터 만 사용 했 기 때문 이 다 . 반환 된 이 함수 가 한 개 의 파라 매터 만 받 는 함수 를 다시 한 번 반환 한다면 … … 상상 이 되 는가 ? 마지막 반환 된 함수 를 실행 하 면 이미 전달 한 두 개 의 파라 매터 가 클로 져 로 캡쳐 된 상태 이 고 실제 실행 할 함수 에 고정 값 으로 전달 할 수 있 다 . 고정 된 값 이 각각 parseInt 의 string 과 radix 에 들어갈 녀석 이 라고 하 면 2 진수 를 정수 를 반환 하 는 함수 를 만들 수 있 을 것 이 다 . 
 두 개 의 인자 를 고정 하 는 curry 2 는 curry 와 비슷 한 구조 로 만들 수 있 다 . 함수 를 반환 하 는 단계 가 더 추가 되 었 다 . 
 curry 2 ( parseInt ) ( 2 ) 를 한 단계 씩 추적 해 보 자 . 
 반환 된 함수 는 인자 를 한 개 만 받 는데 그것 이 arg 2 이 고 parseInt 의 radix 로 들어갈 녀석 이 다 . 
 반환 된 함수 는 인자 를 한 개 만 받 는데 그것 이 arg 1 이 고 parseInt 의 string 으로 들어갈 놈 이 다 . 
 ‘ 11 ’ 값 을 전달 해서 실행 하 면 parseInt ( ‘ 11 ’, 2 ) 의 실행 결과 를 반환 한다 . 
 parseInt 는 파라 매터 두 개 를 한 번 에 전달 받 아 실행 하 는 함수 였 다 . curry 2 를 이용 해 parseInt 를 하나 의 인자 만 받 도록 강제 했 고 최종 적 으로 parseInt 를 실행 하 기 위해서 는 세 번 의 함수 호출 이 필요 하 다 . 각 함수 는 파라 매터 를 1 개 만 받 는데 각 각 parseInt , 2 , ‘ 11 ’ 이 전달 된다 . 즉 2 개 인자 를 받 는 함수 를 1 개 인자 를 받 는 함수열 로 변경 한 모습 이 다 . 앞서 언급 한 커 링 의 정의 를 구체 적 으로 보여 주 는 예제 다 . 
 커 링 된 함수 parseBinaryString 을 맵 함수 의 콜백 함수 로서 전달 하 면 의도 한 결과 를 얻 을 수 있 다 . 
 코드 가 간결 하 고 가독성 도 좋 다 . 이것 을 커 링 없이 코딩 한다면 다음 과 같 을 것 이 다 . 
 어떤 코드 가 좋 은 지 는 개인 의 취향 이 다 . 
 커 링 을 이용 한 플 루 언 트 API 
 처음 질문 을 상기 해 보 자 . 왜 커 링 을 사용 할까 ? 이제 는 답 할 수 있 다 . 가독성 과 확장 성 이 다 . 지금 까지 만든 코드 를 정리 해 보 자 . 
 curry , curry 2 함수 를 이용 해 parseDecimalString , parseBinaryString 함수 를 만들 었 다 . 아직 parseInt 를 실행 하 진 않 았 다 . 단지 이 함수 들 은 parseInt 를 실행 할 코드 를 담 고 있 다 . 이 부분 이 중요 하 다 . parseInt 를 바로 실행 하 지 않 고 함수 실행 을 몇 단계 로 쪼개 놓 았 다 . 그래서 인자 를 미리 설정 한 뒤 다른 역할 을 하 는 새로운 함수 를 만들 어 냈 다 . 
 함수 를 이용 해 함수 를 만든 다는 맥락 에서 볼 때 커 링 은 넓 은 기능 의 함수 를 특정 기능 만 하 도록 좁히 는 능력 을 가지 고 있 다 . parseInt 는 string , radix 둘 다 한 번 에 전달 해서 문자열 을 다양 한 진법 의 숫자 로 변환 한다 . 이것 을 커 링 하 게 되 면 파라 매터 로 넘긴 radix 를 고정 시켜서 10 진수 또는 2 진수 정수 만 만드 는 새로운 함수 가 된다 . 
 parseInt 함수 는 여러 가지 역할 을 할 수 있 기 때문 에 그 파라 매터 를 확인 해야 지만 정확 한 기능 을 읽 을 수 있 다 . 반면 커 링 된 함수 는 이름 만 으로 도 어떤 일 을 하 는지 쉽 게 파악 할 수 있 다 . 두 코드 를 비교 해 보 자 . 
 [ ‘ 11 ’, ‘ 11 ’, ‘ 11 ’, ‘ 11 ’]. map ( parseDicimalString ) 
 [ ‘ 11 ’, ‘ 11 ’, ‘ 11 ’, ‘ 11 ’]. map ( parseBinaryString ) 
 어떤 것 이 가독성 이 좋 은가 ? 커 링 된 함수 다 . 함수 를 할당 한 변수 이름 을 잘 지어서 그런 거 라고 ? 변수 없이 사용 해 보 자 . 
 [ ‘ 11 ’, ‘ 11 ’, ‘ 11 ’, ‘ 11 ’]. map ( curry ( parseInt ) ) 
 [ ‘ 11 ’, ‘ 11 ’, ‘ 11 ’, ‘ 11 ’]. map ( curry 2 ( parseInt , 2 ) ) 
 여전히 커 링 을 사용 한 코드 의 손 을 들 어 주 고 싶 다 . 가독성 측면 에서 다른 예 를 하나 더 제시 하 고 글 을 마무리 하 겠 다 . 
 정수 값 이 특정 범위 에 있 는지 체크 하 는 함수 withInRange 는 다음 과 같이 만들 수 있 다 . 
 솔직히 이런 조건문 을 마주칠 때 마다 몇 초간 멈칫 한다 . 유심히 조건문 을 해석 하 며 의도 를 파악 하 기 위해서 다 . 그럼 이런 코드 는 어떨까 ? 
 그냥 읽 으면 된다 . 영어 권 사람 들 은 비 개발자 도 읽 을 수 있 는 코드 다 . 
 아래 checker 는 함수 을 받 아서 함수 를 반환 하 는 고차 함 수다 . 
 인자 로 받 는 함수 는 검 증자 로서 여기 서 는 30 보다 큰 지 50 보다 작 은지 를 검사 한다 . 그리고 검증 대상 이 되 는 인자 를 받 는 함수 를 반환 한다 . 
 인자 는 val 변수 로 들어오 는데 이전 호출 에서 갭 쳐 된 validators 를 리듀스 로 돌리 면서 하나 씩 체크 한다 . vali ( val ) 로 값 을 검증 하 는데 vali 는 참 / 거짓 을 반환 하 는 함수 여야 한다 . 모든 검증 에 통과 하 면 true 를 반환 하 고 그렇 지 않 으면 false 를 반환 하 는 것 이 checker 의 역할 이 다 . 
 같 은 방법 으로 lesstThan ( ) 함수 도 만들 수 있 다 . 
 greaterThan ( ) 과 lessThan ( ) 함수 로 만든 검증 자 함수 를 checker 의 인자 로 전달 할 수 있 다 . 왜냐면 체커 는 참 / 거짓 을 반환 하 는 함수 를 인자 로 받 기 때문 이 다 . 
 greaterThan ( 30 ) , 
 lessThan ( 50 ) 
 parseInt 는 두 개 인자 를 받 고 곧장 문자열 을 파싱 한 정수 값 을 반환 하 는 함수 다 . 반면 parseInt 를 커 링 하 면 전달 한 인자 하나 씩 만 받 는 함수열 을 반환 한다 . 이 함수 에 인자 를 전달 하 는 행위 는 parseInt 를 특정 기능 만 하 도록 행동 을 구체 화 하 는 것 이 다 . 
 커 링 된 함수 는 코드 의 가독성 을 높인다 . 게다가 커 링 된 함수 는 함수 를 파라 매터 로 받 는 고차 함수 와 결함 하 여 함수 조립 이 가능 하 다 . 
 아마도 curry 2 처럼 3 , 4 , 5 , … , n 개 인자 를 커 링 하 는 함수 를 생각 할지 도 모르 겠 다 . 실행 한다면 아마도 이런 모습 일 것 이 다 . curry 10 ( ) ( ) ( ) ( ) ( ) ( ) ( ) ( ) ( ) ( ) ( ) 괴상 하 다 . 커 링 이 인자 를 하나 씩 받 아 고정 한 반면 , 여러 인자 를 한 번 에 받 아 고정 시키 는 것 을 우리 는 부분 적용 이 라고 부를 것 이 다 . 다음 글 에서 소개 하 겠 다 . 
 다음 글 : ( 함수 형 JS ) 함수 로 함수 만들 기 3 부분 적용