반응형
인프런 - 함수형 프로그래밍과 JavaScript ES6+ (inflearn.com)
해당 강의 공부 중....!
코드를 값으로 다루어 표현력 높이기
go
- args를 함수로 축약하는 함수
- 인자를 계속해서 전달해나감
// 이전 리듀스...
const reduce = (f, acc, iter) => {
if (!iter) { // 인자 2개이거나 iterator가 아니면
iter = acc[Symbol.iterator]();
acc = iter.next().value;
}
for (const value of iter) {
acc = f(acc, value);
}
return acc;
};
const add = (a, b) => a + b;
// ...args =? args는 리스트가 됨 [1, f ,f ,f]
const go = (...args) => reduce((a, f) => f(a), args); // ...args가 배열로 바뀜
// args를 특정 함수로 축약하는 함수
// a인자 위치가 acc 위치, f위치가 원래 value 위치인데 함수가 옴
// 인자가 2개이므로 args의 이터레이터를 뽑아오고 acc는 첫값(1)이 된다.
// ((a, f) => f(a))(acc, value)가 되는꼴이므로 이전 함수 결과의 누적 값에 함수를 적용함
go(
add(0, 1), // 1
a => a + 10, // 10
a => a + 100, // 100
log);// 111
pipe
- go 함수를 리턴하는 함수
- go는 즉시 평가
- 함수 평가 결과를 누적하여 연쇄 적용
- 함수들이 나열되어 있는 합성 함수
- go는 즉시 평가
const pipe0 = (...fs) => (a) => go(a,...fs);
// 함수 배열을 전개하여 인자로 넣으면 go 함수를 리턴. a를 초기값으로 받아서 수행
// 첫번째 함수는 인자를 여러개 받을 수 있게 개조해준 함수
// 해당값 적용 값이 누적 시작값이 됨.
const pipe = (f, ...fs) => (...as) => go(f(...as), ...fs);
const f = pipe(
(a, b) => a + b,
a => a + 10,
a => a + 100); // (...as) => go(f(...as), ...fs);
log(f(0, 1)); // (1,2) =>go(add(1,2)
go로 더 읽기 좋은 함수 만들기
// 조합하던 함수를 위에서 아래로 펼칠 수 있게 됨.
go(
products,
products => filter(p => p.price < 20000, products),
products => map(p => p.price, products),
prices => reduce(add, prices),
log);
curry
- 함수를 값으로 다룸
- 함수를 원하는 시점에 평가
- 함수를 받아서 함수를 리턴
- 인자를 받아서 원하는 인자 만큼 들어왔을 때 평가함
const curry = f =>
(a, ..._) => _.length ? f(a, ..._) : (..._) => f(a, ..._);
// 1. f 함수를 받아서 함수를 리턴함.
// 2. _.length 함수 인자 2개 이상? f 즉시 실행
// 3. 아니라면 함수를 리턴한 후에 인자를 더 받아서 실행
const mult = curry((a, b) => a * b);
mult(3)// 함수 리턴
log(mult(3)(2)); // 6
// 아래 모든 함수들이 인자가 하나만 들어오면 나머지 인자를 기다리도록 되어 있음.
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;
});
// a를 나중에 받아서 실행할 수 있음
// filter(p => p.price < 20000)는 리턴 결과가 함수임.
go(
products,
filter(p => p.price < 20000),
map(p => p.price),
reduce(add),
log
);
함수 조합으로 함수 만들기
// 첫번째 함수는 인자를 여러개 받을 수 있게 만든 지연 평가 함수
// 해당값 적용 값이 누적 시작값이 됨.
const pipe = (f, ...fs) => (...as) => go(f(...as), ...fs);
// 파이프라인 코드 중복 제거
// go + curry + pipe
const total_price = pipe(map(p => p.price),
reduce(add))
// before
go(
products,
filter(p => p.price < 20000),
map(p => p.price),
reduce(add),
log
);
// after
go(
products,
filter(p => p.price < 20000),
total_price,
log
);
// 중복 제거를 위한 지연 평가 함수
const total_price = pipe(
map(p => p.price),
reduce(add));
// filter 인수 predicate 함수를 받아서 pipe를 만드는 함수
const base_total_price = predi => pipe(
filter(predi),
total_price); // total_price가 여기에 들어가 있음.
// 파이프는 값이 들어와야 실행됨
go(
products,
base_total_price(p => p.price < 20000),
log);
반응형