const products = [
{name: '반팔티', price: 15000},
{name: '긴팔티', price: 20000},
{name: '핸드폰케이스', price: 15000},
{name: '후드티', price: 30000},
{name: '바지', price: 25000}
];
const add = (a, b) => a + b;
log(
reduce(
add,
map(p => p.price,
filter(p => p.price < 20000, products))));
console.clear();
코드를 값으로 다루어 표현력 높이기
[go, pipe]
const go = (...args) => reduce((a, f) => f(a), args);
// 리스트로 받는다
// 인자를 연속적으로 전달 -> 리듀스 라는 이야기
// args를 하나의 값으로 축약하는 과정
// 연산이 연속적으로 일어나서 하나의 값을 만드는 함수
go(
add(0, 1), // 첫번째 인자는 값
a => a + 10,
a => a + 100,
log);
// 111
const pipe = (f, ...fs) => (...as) => go(f(...as), ...fs);
// 함수를 값으로 하기 때문에 내부에서 go를 사용
// ...as 는 축약된 함수, 실행되는 첫번째 함수가 인자를 여러개 받기 위해서 전개를 함
// 여러개!!
// 합성된 축약된 함수를 만드는 함수
const f = pipe(
(a, b) => a + b,
a => a + 10,
a => a + 100);
log(f(0, 1));
console.clear();
[위 함수 이용해서 개선]
log(
reduce(
add,
map(p => p.price,
filter(p => p.price < 20000, products))));
// go 함수 이용해서 순서를 더 명확하게 뒤집음
go(
products,
products => filter(p => p.price < 20000, products),
products => map(p => p.price, products),
prices => reduce(add, prices),
log);
[curry]
- 인자가 두 개 이상 모였을때 실행 시키는 함수
- 함수를 값으로 받으면서 원하는 시점에 평가 시작
- 필요 인자가 2개 이상 일때만 쓰도록 하자
const curry = f => (a,..._) => _.length ? f(a, ..._) : (..._) => f(a, ..._);
// 2개 이상일때가 원하는 시점
// 인자가 2개 이상이면 해당 함수를 실행하고
// 아니면 인자를 더 받아야하는 함수 리턴하고 나중에 받은 인자까지 합쳐서 실행하는 함수
const mult = curry((a, b) => a * b);
// 함수를 일단 등록
// case1 두개 이상 등록시
log(mult(3, 2)); // 6
// case2 하나만 등록시
const mult3 = mult(3); // 3이 미리 들어 가있고 추가 인자 전달시 값이 나오는 함수
log(mult3(10));
log(mult3(5));
log(mult3(3));
console.clear();
[Curry 적용으로 개선]
const log = console.log;
const curry = f =>
(a, ..._) => _.length ? f(a, ..._) : (..._) => f(a, ..._);
// map filter reduce 함수의 경우 해당 구조로 감싸게 되면
// map filter reduce 함수가 먼저 등록되고
// 조건 함수가 등록될 때 인자가 1개기 때문에 또 다시 인자를 받는 함수가 반환이 되기 때문에 유용하다
// 조금 더 간결해진다
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;
});
// 예시
const products = [
{ name: "반팔티", price: 15000 },
{ name: "긴팔티", price: 20000 },
{ name: "핸드폰케이스", price: 15000 },
{ name: "후드티", price: 30000 },
{ name: "바지", price: 25000 }
];
const enrolledMap = map(p => p.price);
console.log(enrolledMap); // 함수
console.log(enrolledMap(products)); // [15000, 20000, 15000, 30000, 25000]
log(
reduce(
add,
map(p => p.price,
filter(p => p.price < 20000, products))));
// 1단계 go만 적용 했을때
go(
products,
products => filter(p => p.price < 20000, products),
products => map(p => p.price, products),
prices => reduce(add, prices),
log);
// 2단계 curry 까지 적용 했을때
go(
products,
products => filter(p => p.price < 20000)(products),
// filter(p => p.price < 20000)는 일단 함수를 받고 기다릴 수 있다
// products => 실행함수(products)는 어짜피 go 안의 reduce안에서 축약된다
// 실행 함수만만 제대로 전달이 되면 된다
products => map(p => p.price)(products),
prices => reduce(add)(prices),
log);
go(
products,
filter(p => p.price < 20000),
// 인자를 하나만 받아서 반환 값이 조건함수 물고있는 함수
map(p => p.price),
reduce(add),
log);