본문 바로가기
NodeJS/FuncP

Go, Pipe, Curry

by MiteDev 2024. 2. 20.

2024.02.19 - [NodeJS/FuncP] - 함수형 프로그래밍이란?

 

함수형 프로그래밍이란?

함수형 프로그래밍? 함수형 프로그래밍 (Funtional Programming)이란 자료 처리를 수학적 함수의 계산으로 취급하고 상태와 가변 데이터를 멀리하는 프로그래밍 패러다임의 하나이다. - [위키백과] -

odhok.tistory.com

위 글을 읽고 오시는걸 추천합니다

go 함수란 무엇일까?

go는 함수들을 인자로 받아서 함수를 통과시킨 결과값을 return 해주는 함수다. 말로만 들으면 무슨말인지 이해가 어려우니 코드를 보도록 하자.

const go = (...args) => args.reduce((acc, cur) => cur(acc));
/*
    const go = (...args) => {
    	return args.reduce((acc, cur) => {
        	return cur(acc);
    	})
    }
*/

go(
    10, // 초기값
    a => a + 1,
    a => a + 10,
    a => a + 100,
    console.log
) // result: 121

 

이게 끝이다. 인자로 제공된 함수의 return값을 계속 누적시켜나가는 것이 go이기 때문에 js의 내장 함수인 reduce를 사용해 go 함수를 만들 수 있다. args에 대한 reduce가 실행되면 acc에는 args 배열의 첫 번째 인자인 10이 cur에는 a => a + 1이 할당된다. 

 

  acc, cur 할당 순서는 다음과 같다

acc cur
10 a => a + 1
11 a => a + 10
21 a => a + 100
121 console.log

 

 

그럼 pipe 함수는?

  pipe는 함수를 인자로 받아 함수를 return 하는 함수다. 즉, 합성함수를 만들어주는 함수이다. 이 또한 말로만 들으면 무슨 소리인가 싶으니 직접 코드를 보자

const pipe = (...funcs) => (init_v) => funcs.reduce((acc, cur) => cur(acc), init_v);

/*
    const pipe = (...funcs) => {
    	return (init_v) => {
            return funcs.reduce((acc, cur) => {
                return cur(acc); 
            }, init_v)
        }
    }
*/

const pipeFunc = pipe(
    a => a + 1,
    a => a + 10,
    a => a + 100,
    console.log
)

pipeFunc(0);

 

  pipe 함수는 함수들을 받고 초기값을 받아 함수들에 대한 reduce를 실행시키는 클로저를 리턴해준다. 근데 init_v => funcs.reduce((acc, cur) => cur(acc), init_v)를 보면 초기값을 주고 실행시킬 함수가 들어있는 funcs 배열에 reduce를 실행시키는 것을 보면 go 함수와 동작이 동일하다. 즉 pipe는 내부적으로 go를 이용해서 동작한다.

const go = (...args) => args.reduce((acc, cur) => cur(acc));

const pipe = (...funcs) => (init_v) => go(init_v, ...funcs)

const pipeFunc = pipe(
    a => a + 1,
    a => a + 10,
    a => a + 100,
    console.log
)

pipeFunc(0);

 

마지막으로 curry란 무엇일까?

  curry란 함수를 인자로 받으면서 받아둔 함수를 원하는 시점에 평가시키는 함수이다. 

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

/*
    const curry = f => {
    	return (a, ..._) => {
        	return _.length ? f(a, ..._) : (..._) => {
            	return f(a, ..._);
        	}
    	}
    }
*/

const mult = (a, b) => a * b;

const multCurry = curry(mult);

console.log(multCurry(3)); // (..._) => f(a, ..._)
console.log(multCurry(3)(5)); // 15

 

curry 함수는 첫 인자를 함수로 받고 이후에 인자가 2개 이상 들어왔을 때 평가하는 함수이다.

예시에서 보듯 mult 함수를 curry 함수의 인자로 준 multCurry 함수를 만들고 인자를 하나씩 넣어주면 하나만 넣었을 때는 함수를 반환하지만 인자를 2개 넣어주면 결과를 반환해준다.

 

 위의 go 함수와 조합하는 방법도 있었는데 코드는 아래와 같다. curry 함수는 보기 편하게 일반적인 함수 형태로 변경해두었다.

const go = (...args) => args.reduce((acc, cur) => cur(acc));

const curry = f => {
    return (a, ..._) => {
        console.log('f:', f);
        console.log('a:', a);
        return _.length ? f(a, ..._) : (..._) => {
            console.log('..._', _);
            return f(a, ..._);
        }
    }
}

const products = [
    { name: '반팔티', price: 15000 },
    { name: '긴팔티', price: 20000 },
    { name: '핸드폰케이스', price: 15000 },
    { name: '후드티', price: 30000 },
    { name: '바지', price: 25000 },
];

const c_map = curry((fn, arr) => arr.map(fn));
const c_filter = curry((fn, arr) => arr.filter(fn));
const c_reduce = curry((fn, arr) => arr.reduce(fn))

// curry 미적용
go(
    products.map(p => p.price),
    price => price.filter(p => p < 20000),
    price => price.reduce((acc, cur) => acc + cur),
    console.log
)

// curry 적용
go(
    products,
    c_map(p => p.price),
    c_filter(p => p < 20000),
    c_reduce((acc, cur) => acc + cur),
    console.log
)

 

  내장함수인 map, filter, reduce를 curry로 묶고 go에 넣으면 계산할 인자의 전달을 curry 함수에 위임할 수 있다. curry 함수 내부에서 로그를 찍어보면 아래와 같이 나온다.

curry의 인자인 f, a, ..._에 들어있는 값들은 차례대로 아래의 표와 같다.

f (fn, arr) => arr.map(fn) (fn, arr) => arr.filter(fn) (fn, arr) => arr.reduce(fn)
a p => p.price p => p < 20000 (acc, cur) => acc + cur
..._ [products] [ [ 15000, 20000, 150000, 30000, 25000 ] ] [ [ 15000, 15000] ]

 

로그가 출력되는 순서를 보면 함수들이 먼저 만들어지고 이후에 값이 들어가기 시작할 때 평가가 된다는것을 알 수 있다.

'NodeJS > FuncP' 카테고리의 다른 글

Iterator, Iterable  (0) 2024.02.19
함수형 프로그래밍이란?  (2) 2024.02.19