[JS] 함수형 프로그래밍 입문 #3

본 강좌는 유인동님의 함수형 프로그래밍과 JavaScript ES6+ 강좌를 듣고 정리한 것입니다. 개인 학습용으로 유료 강좌 내용 전부가 아닌 유인동님의 깃허브에 공개된 자료를 바탕으로 코드를 요약 정리했습니다. 문제시 자삭하도록 하겠습니다.

함수형 프로그래밍 입문 #3

go

함수가 연속적으로 실행되도록 하는 함수 (함수는 넘겨지자마자 실행된다, 마지막엔 값이 리턴되겠지?)

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

go(
	0,
	a => a + 1,
	a => a + 10,
	a => a + 100,
	log);

// go를 사용해 기존의 코드를 리팩토링해보면

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

pipe

합성 함수를 만드는 함수 (함수를 리턴한다)

내부에서 go를 사용한다

const go = (...args) => reduce((a, f) => f(a), args);
const pipe = (...fs) => (a) => go(a, ...fs);


const f = pipe(
	a => a + 1,
    a => a + 10,
    a => a + 100);

log(f(0)); // go 함수와 같다

// 좀 더 생각해본다면

const f = pipe(
	(a, b) => a + b,
    a => a + 10,
    a => a + 100);

log(f(0, 1)) // 이렇게도 결과값이 나오면 좋겠다. 만들어보자.
const pipe = (f, ...fs) => (...as) => go(f(...as), ...fs);

curry

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

//    함수를 받고 
//     => 첫번째 인자, 나머지 인자를 받고
//     => 인자가 2개 이상이라면 받아둔 함수를 즉시 실행하고
//     => 두 개 보다 작다면 함수를 다시 리턴한 후에 그 후에 받은 인자를 합쳐서 실행

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

// 곱셉하는 함수가 있다고 가정하면
const mult = (a, b) => a * b;
// 이걸 커리로 한 번 감싸주면
const mult = curry((a, b) => a * b);
// 로그로 찍어보면 당연히 curry 함수가 나오고
log(mult);	// (a, ..._) => _.length ? f(a, ..._) : (..._) => f(a, ..._)
// 인자를 하나 넣어 실행했을 때도 인자가 하나니까 함수가 나온다
log(mult(1)); // (..._) => f(a, ..._) 
// 인자를 하나 더 넣어서 실행시켜주면 받아두었던 원래의 f 함수 (여기선 곱하는 mult 함수)가 실행된다
log(mult(1)(2)) // 2


// 이건 이런 패턴으로 활용할 수 있다
const mult3 = mult(3);
log(mult3(10)) // 30
log(mult3(20)) // 60

// 코드를 좀 더 간결하게 만들 수 있다는 소리기도 한데, 위의 코드를 리팩토링해보면
// (map, filter, reduce를 모두 curry로 감쌌다고 생각한다면)

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

// 이걸 잘 살펴보면 products를 받아서 products를 평가한다는 이야기니까 이렇게 바꿀 수 있다
go (
	products,
	filter(p => p.price < 20000),
    map(p => p.price),
    reduce(add),
    log)

순서를 바꾸는 go 함수, 함수를 부분 실행하는 curry를 통해 가독성이 높아진다

조합

// 20000원 이상인 상품을 구하는 코드와 이하인 상품을 구하는 코드의 중복 지점을 없애보자
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),
    log)

// 이미 분리가 잘 되어 있으므로 map,reduce 를 하나의 함수로 빼주면

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

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

// 좀 더 분리해보면 함수를 넘겨줄 수도 있다

const base_total_price = predi => pipe(
	filter(predi),
	total_price,
)

go (
	products,
	base_total_price(p => p.price < 20000),
    log)
    
go (
	products,
	base_total_price(p => p.price >= 20000)
    log)
 Date: 
 Tags:  JS