본 포스트는 인프런의 함수형 프로그래밍과 JavaScript ES6+ 강의(링크)를 듣고 정리한 내용입니다.
const products = [
{ name: "반팔티", price: 15000 },
{ name: "긴팔티", price: 20000 },
{ name: "핸트폰케이스", price: 15000 },
{ name: "후트티", price: 30000 },
{ name: "바지", price: 25000 },
];
const go = (...args) => {
return reduce((a, f) => f(a), args);
};
go(
0,
(a) => a + 1,
(a) => a + 10,
(a) => a + 100,
console.log
);
//111
go
라는 함수를 만들어 보았다.
인자의 첫번째 인자를 다음 함수로 전달하고 그 함수의 결과를 다음 함수의 인자로 전달한다.
reduce
의 f로 (a, f) => f(a)
가 들어가게 된다.
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;
};
f = (a, f) => f(a), acc = 0, iter = [(a) => a + 1, (a) => a + 10, (a) => a + 100, console.log]
//1번 순회
acc = f(0, (a) => a + 1) = 1
f(0, (a) => a + 1) = (0, (a) => a + 1) => f(a) = 0 + 1 = 1
//2번 순회
acc = f(1, (a) => a + 10) = 11
f(1, (a) => a + 10) = (1, (a) => a + 10) => f(a) = 1 + 10 = 11
//3번 순회
acc = f(11, (a) => a + 100) = 111
f(11, (a) => a + 100) = (11, (a) => a + 100) => f(a) = 11 + 100 = 111
//4번 순회
acc = f(111, console.log) //111
f(111, console.log) = (111, console.log) => f(a) = console.log(111) //111
const pipe = (...fs) => {
return (b) => go(b, ...fs);
};
const f = pipe(
(a) => a + 1,
(a) => a + 10,
(a) => a + 100
);
console.log(f(0));
//111
pipe
라는 함수를 만들어 보았다.
함수들을 인자로 받아서 합성된 함수를 리턴해준다.
go
함수의 인자로 변수 a와 함수들을 넣어준다.
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 go = (...args) => {
return reduce((a, f) => f(a), args);
};
go(
b,
(a) => a + 1,
(a) => a + 10,
(a) => a + 100,
);
f = (a, f) => f(a), acc = b, iter = [(a) => a + 1, (a) => a + 10, (a) => a + 100]
//1번 순회
acc = f(b, (a) => a + 1) = b + 1
f(b, (a) => a + 1) = (b, (a) => a + 1) => f(a) = b + 1
//2번 순회
acc = f(b + 1, (a) => a + 10) = b + 11
f(b + 1, (a) => a + 10) = (b + 1, (a) => a + 10) => f(a) = b + 1 + 10 = b + 11
//3번 순회
acc = f(b + 11, (a) => a + 100) = b + 111
f(b + 11, (a) => a + 100) = (b + 11, (a) => a + 100) => f(a) = b + 11 + 100 = b + 111
const f = pipe(
(a) => a + 1,
(a) => a + 10,
(a) => a + 100
);
//b + 111
go(
add(0, 1),
(a) => a + 10,
(a) => a + 100,
console.log
);
go
함수의 경우는 초기 인자들을 함수의 내부에 집어 넣어 처리해준다.const pipe = (f, ...fs) => {
return (...as) => go(f(...as), ...fs);
};
const f = pipe(
(a, b) => a + b,
(a) => a + 10,
(a) => a + 100
);
console.log(f(0, 1));
pipe
함수의 경우는 첫 함수를 여러개의 인자를 받는 형태로 바꿔줘야 한다.pipe
함수가 받는 첫 함수와 그이후 함수들을 분리해주고, 초기 인자들을 첫 함수로 처리해준다. const add = (a, b) => a + b;
console.log(
reduce(
add,
map(
(p) => p.price,
filter((p) => p.price < 20000, products)
)
)
);
//30000
go
함수를 써서 읽기 좋게 만들어 보자go(
products,
(products) => filter((p) => p.price < 20000, products),
(products) => map((p) => p.price, products),
(prices) => reduce(add, prices),
console.log
);
//30000
go
함수를 사용했더니 더 읽기 좋은 코드가 되었다.const curry = (f) => (a, ..._) => _.length ? f(a, ..._) : (..._) => f(a, ..._);
// _의 길이가 있다면 인자가 2개 이상이다.
const mult = curry((a, b) => a * b);
console.log(mult(3)(2)); //6
const mult3 = mult(3);
console.log(mult3(10)); //30
console.log(mult3(5)); //15
console.log(mult3(3)); //9
curry
라는 함수를 만들어 보았다.go(
products,
(products) => filter((p) => p.price < 20000, products),
(products) => map((p) => p.price, products),
(prices) => reduce(add, prices),
console.log
);
//30000
go
함수를 써서 읽기 좋게 만든 코드이다.//fx.js
const map = curry((f, iter) => {
let res = [];
for (const a of iter) {
res.push(f(a));
}
return res;
});
const filter = curry((f, iter) => {
let 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;
});
filter
reduce
map
에 전부 curry
를 적용해 보았다.go(
products,
(products) => filter((p) => p.price < 20000)(products),
(products) => map((p) => p.price)(products),
(prices) => reduce(add)(prices),
console.log
);
//30000
curry
를 적용하여 바뀐 코드를 보면 filter
reduce
map
에서 products를 인자로 받아 각각에 함수에 다시 products를 넣어주는 형태이므로 products를 제거해보도록 하겠다.go(
products,
filter((p) => p.price < 20000),
map((p) => p.price),
reduce(add),
console.log
);
//30000
const toal_price = pipe(
map((p) => p.price),
reduce(add)
);
go(
products,
filter((p) => p.price < 20000),
toal_price,
console.log
);
pipe
함수를 이용하여 단축하였다.const base_total_price = predi => pipe(
filter(predi),
toal_price
)
go(
products,
base_total_price((p) => p.price < 20000),
console.log
);
filter
함수 부분까지도 단축시켜 보았다.