[JavaScript] go, curry 함수를 만들어 읽기 좋은 코드 만들기

2023. 4. 29. 02:35· Node.js/JS
목차
  1. Curry
  2. 함수 조합으로 함수 생성

https://dev-scratch.tistory.com/151

 

[JavaScript] go, pipe로 읽기 좋은 코드 만들기

기존 함수의 문제 https://dev-scratch.tistory.com/150 [JavaScript] Map + Filter + Reduce 중첩 사용과 함수형 사고 Map, Filter, Reduce 중첩하여 사용 map, filter, reduce 함수를 커스텀으로 생성하고, 이를 중첩하여 사용

dev-scratch.tistory.com

이제 위 게시물의 가장 상단 복잡했던 코드들을 아래와 같이 작성할 수 있다.

 

먼저 원본 코드는 아래와 같다.

const filter = (f, iter) => {
	const res = [];
    for (const a of iter) {
	    if (f(a)) res.push(a);
    }
    return res;
};

const reduce = (f, acc, iter) => {
	if (!iter) {
	    iter = acc[Symbol.iterator]();
        acc = iter.next().value;
    }
    for (const a of iter) {
	    acc = f(acc, a);
    }
    return acc;
};
const products = [
	{ name: '반팔티', price: 15000 },
    { name: '긴팔티', price: 20000 },
    { name: '핸드폰케이스', price: 15000 },
    { name: '후드티', price: 30000 },
    { name: '바지', price: 25000 },
];
const add = (a, b) => a + b;

reduce(add, map(p => p.price, filter(p => p.price < 20000, products))));

 

이 함수를 go 함수를 사용해 아래와 같이 가독성 좋게 표현할 수 있다.

 

const go = (...args) => reduce((a, f) => f(a), args);
const add = (a, b) => a + b;

go(
	products,
    products => filter(p => p.price < 20000, products),
    products => map(p => p.price, products),
    products => reduce(add, prices),
    console.log
);

위 함수는 위에부터 아래로 읽으면서 전체 흐름을 한 눈에 파악하기 좋다.

 

Curry

Curry 함수는 함수를 값으로 다루면서, 받아둔 함수를 내가 원하는 시점에서 평가하는 함수이다.

함수를 받아서 함수를 리턴하고, 인자를 받아서 원하는 인자 개수만큼 들어왔을 때 받아두었던 함수를 나중에 평가시킨다.

 

const curry = f => 
	(a, ..._) => _.length
    ? f(a, ..._)
    : (..._) => f(a, ..._);

위 함수는 첫 번째 매개변수와 나머지 함수 인자를 받아들인다. 이때, 총 인자가 2개 이상인 경우에는 인자와 함께 그 함수를 실행하고, 아니면 그 이후에 받은 인자들을 합쳐서 실행하는 함수이다.

 

const multiple = curry((a, b) => a * b);

multiple(1);

만약 이렇게 값을 받아서 사용하게 된다면, multiple 의 반환값은 아래와 같다. 위에서 거짓인 경우의 상황인 것이다.

(..._) => f(a, ..._)

이때, 한 번 더 값을 불러오면 원하는 값을 얻어낼 수 있다.

multiple(1)(2);
// 2

multiple(2)(3);
// 6

혹은 미리 변수에 첫 번째 함수를 반환하는 함수를 평가해 변수에 함수의 포인터를 전달하여 사용할 수도 있다.

const multiple3 = multiple(3);

multiple3(10);
// 30

multiple3(5);
// 15

multiple3(3);
// 9

 

그러면 이제 go와 curry를 혼합해 더 가독성이 좋은 코드를 만들어 볼 수 있다.

 

const map = curry((f, iter) => {
	const res = [];
	for (const a of iter) {
	    res.push(f(a))
    }
    return res;
});

const filter = curry((f, iter) => {
	const res = [];
    for (const a of iter) {
	    if (f(a)) res.push(a);
    }
    return res;
});

const reduce = curry((f, acc, iter) => {
	if (!iter) {
	    iter = acc[Symbol.iterator]();
        acc = iter.next().value;
    }
    for (const a of iter) {
	    acc = f(acc, a);
    }
    return acc;
});

이때, go 함수를 사용할 때는 아래와 같이 사용할 수 있다.

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

go(
	products,
    products => filter(p => p.price < 20000)(products),
    products => map(p => p.price)(products),
    products => reduce(add)(prices),
    console.log
);

여기서 이 과정을 조금 더 축약할 수 있는데, 다음과 같다.

go(
	products,
    filter(p => p.price < 20000),
    map(p => p.price),
    reduce(add),
    log
);

 

함수 조합으로 함수 생성

아래와 같이 거의 비슷한 함수가 있다고 가정해보자.

go(
	products,
    filter(p => p.price < 20000),
    map(p => p.price),
    reduce(add),
    console.log
);

go(
	products,
    filter(p => p.price >= 20000),
    map(p => p.price),
    reduce(add),
    console.log
);

여기서는 map과 reduce가 겹치기에 추가적으로 조합을 사용해 간단히 나타낼 수 있다.

const total_price = pipe(
	map(p => p.price),
    reduce(add)
);

go(
	products,
    filter(p => p.price < 20000),
    total_price,
    console.log
);

go(
	products,
    filter(p => p.price >= 20000),
    total_price,
    console.log
);

pipe를 사용해 함수들을 등록한 후, 향후에 트리거할 수 있도록 함수 포인터만 받아서 다시 go 함수에 전달한다.

 

그런데 여기서 filter와 total_price를 사용하는 것이 겹치므로 한 번 더 가공해 표현할 수 있다.

const total_price = pipe(
	map(p => p.price),
    reduce(add)
);

const base_total_price = predict => pipe(
	filter(predict),
    total_price
);

go(
	products,
    base_total_price(p => p.price < 20000),
    console.log
);

go(
	products,
    base_total_price(p => p.price >= 20000),
    console.log
);

 


출처: 인프런 함수형 프로그래밍과 JavaScript ES6+(https://www.inflearn.com/course/functional-es6/dashboard)

 

사실 curry에 대해서 완벽히 이해되지 않아서 조금 아쉽다. 그런데 매력이 느껴졌다. 복잡한 절차형 프로그래밍을 단순하게 함수형 프로그래밍으로 변경시킴으로써 함수를 값으로도 사용할 수 있기에 더욱 가독성 있는 코드, 유지보수하기 원활한 코드가 될 수 있다고 생각한다. curry의 의미를 조금 더 열심히 파악해야겠다.

저작자표시 비영리 (새창열림)

'Node.js > JS' 카테고리의 다른 글

[JavaScript] range와 느긋한 L.range  (0) 2023.04.30
[JavaScript] 이터러블 객체와 순회 함수 응용  (0) 2023.04.30
[JavaScript] go, pipe로 읽기 좋은 코드 만들기  (0) 2023.04.27
[JavaScript] Map + Filter + Reduce 중첩 사용과 함수형 사고  (0) 2023.04.27
[JavaScript] 이터러블 프로토콜과 map, filter, reduce  (2) 2023.04.25
  1. Curry
  2. 함수 조합으로 함수 생성
'Node.js/JS' 카테고리의 다른 글
  • [JavaScript] range와 느긋한 L.range
  • [JavaScript] 이터러블 객체와 순회 함수 응용
  • [JavaScript] go, pipe로 읽기 좋은 코드 만들기
  • [JavaScript] Map + Filter + Reduce 중첩 사용과 함수형 사고
턴태
턴태
import { Dream } from "future";
턴태
턴태의 밑바닥부터 시작하는 de-vlog
턴태
전체
오늘
어제
  • ROOT (187)
    • Node.js (37)
      • ES6 (1)
      • TypeScript (3)
      • Express.js (16)
      • NestJS (16)
      • JS (24)
    • 프론트엔드 (29)
      • CS (5)
    • 백엔드 (1)
      • 검색 (2)
      • Database (1)
    • 기타 툴 (1)
      • git (1)
    • 데브옵스 & 인프라 (19)
      • Kubernetes (15)
      • Docker (2)
      • Monitoring (1)
      • IaC (1)
    • Algorithm (90)
      • Implementation & simulation (5)
      • Math (4)
      • Brute Force (1)
      • String (0)
      • Graph (5)
      • Recursion & Backtracking (19)
      • Divide & Conquer (2)
      • Dynamic Programming (18)
      • Greedy (13)
      • Priority Queue (2)
      • Binary Search (6)
      • Data Structure (7)
      • Shortest Path (5)
      • Minimum Spanning Tree (1)
      • Sorting (1)
      • Prefix Sum (1)
    • Linux (1)
      • Ubuntu (1)
    • Diary (5)
      • Algorithm (1)
      • Conference (1)
      • Retrospective (3)
    • Book (0)
      • Self-Development (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • TypeScript
  • nestjs
  • 자바스크립트
  • Toy Project
  • python
  • 디프만
  • 타입스크립트
  • 인프런
  • node.js
  • Express
  • N과 M
  • 파이썬
  • dynamic programming
  • 함수형 프로그래밍
  • 노드
  • baekjoon
  • 쿠버네티스
  • 인프런X디프만
  • 백준
  • Omuk
  • 오먹
  • GREEDY
  • 익스프레스
  • k8s
  • 백트래킹
  • backtracking
  • 네스트
  • Kubernetes
  • 토이프로젝트
  • 다이나믹 프로그래밍

최근 댓글

최근 글

hELLO · Designed By 정상우.v4.2.1
턴태
[JavaScript] go, curry 함수를 만들어 읽기 좋은 코드 만들기
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.