[TIL] Day-7

yoon Y·2021년 8월 12일
0

데브코스 - TIL

목록 보기
5/19

javascript Es6를 기반으로 하는 함수형 프로그래밍에 대해 배웠다.
함수형 프로그래밍을 처음 배워서 이해하는데 시간이 많이 걸렸다.
내가 생각했을 때 가장 중요한 것은, 어떤 인자가 들어가서 어떤 반환 값이 나오는가를 잘 파악해서 이용해야한다는 것이었다.

어떤 것을 반환하냐에 따라 함수의 실행문이 값이 되거나 함수 자체가 되고,
그 둘은 완전히 다르게 평가되기 때문에 해당 함수가 어떤 것을 반환하는지 잘 파악하고 있어야한다.

함수형 프로그래밍이란?

함수들을 중첩하고 연속적으로 실행시키면서 하나의 값으로 평가되게 만들어,
마지막 일을 처리하는 식으로 코딩하는 것.

  • 함수형 코드를 읽을 때 오 -> 왼
  • 함수형 코드를 짤 때 왼 -> 오
    해당 자리(인자)에 어떤 형태의 값이 들어가야하는지 확인 후 ,
    알맞은 형태의 값으로 평가되도록 코드를 짜면 됨
const products = [
        { name: '반팔티', price: 15000 },
        { name: '긴팔티', price: 20000 },
        { name: '핸드폰케이스', price: 15000 },
        { name: '후드티', price: 30000 },
        { name: '바지', price: 25000 },
    ];

log(reduce( //2만원 이하의 상품들의 값을 합친 값
        add, 
        map(p => p.price, 
	        filter(p => p.price < 20000, products))));


코드를 값으로 다루기

go, pipe, curry함수로 함수형 프로그래밍 코드의 표현력을 높힐 수 있다.

go

  • 함수형 프로그래밍 코드를 읽기 쉽게 표현해주는 함수.
  • 즉시 함수들과 인자를 전달해 즉시 어떤 값을 평가하는데 사용.
  • 값을 반환하는 함수.
  • 초기값이 인수로 전달되고, 전달된 인수로 평가된 반환 값이 다음 함수의 인자가 됨.
    ⇒ 함수 실행 후 반환된 값을 이어지는 함수의 인자에 넣어서 실행하는 것을 반복
const go = (...args) => reduce((a, f) => f(a), args);		

go (
        products, // 시작 liter
        products => filter(p => p.price < 20000, products),
        products => map(p => p.price, products),
        prices => reduce(add, prices),
        console.log);

pipe

  • 함수를 리턴하는 함수.
  • 즉시 실행되지 않고, 반환된 함수를 실행해야 사용할 수 있다.
  • 원하는 초기 인수를 넣어서 실행시키면 내부에서 go()가 실행된다.
  • n개의 함수를 연속적으로 실행하면서, 축약하는 하나의 함수를 만들어서 반환.
const pipe = (...fs) => (a) => go(a, ...fs); // 함수를 반환하는 함수

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

console.log(f(0));

--------------------------------------------------

// 초기 값을 함수의 반환 값으로 하고싶다면?

const pipe = (f, ...fs) => (...as) => go(f(...as), ...fs);

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

console.log(f(0,1));

curry

  • 값으로 받아둔 함수를 내가 원하는 시점(조건)에 실행시키는 함수.
  • 함수를 인자로 받아 함수를 반환.
  • 클로저가 된 매개 변수(변수, 함수)들을 원하는 시점에 쓰는 것.
  • 인수를 하나 일단 넣어 놓고, 다음 인자가 들어올 때 실행.

왜 쓰나요?
go, pipe함수를 사용할 때 인자로 들어가는 함수들을 간략하게 만들어 읽기 쉽게 해준다.

const curry = f => (a, ..._) => _.length ? f(a, ..._) : (..._) => f(a, ..._);
const map = curry((f, iter) => { // 함수를 할당할 때 query에 한 번 싸아서 넣는다
    let res = [];
    for (const a of iter) {
        res.push(f(a));
    }
    return res
    });



// filter, map, reduce를 curry의 인수에 넣었다고 할 때,
// 1단계
go (
        products, // 시작 liter
        products => filter(p => p.price < 20000, products),
        products => map(p => p.price, products),
        prices => reduce(add, prices),
        console.log);

// 2단계
go(
    products,          
    products => filter(p => p.price < 20000)(products),
    filteredProducts => map(p => p.price)(filteredProducts),
    prices => reduce(add, prices)(prices),
    console.log);

// 3단계
// 인자 리스트로 함수가 들어가 있으면 자동적으로 
// 인자가 들어가고 결과 값 반환되어 다음 함수의 인자로 넘겨진다
go(
    products,          
    filter(p => p.price < 20000), // (..._) => f(p => p.price < 20000, ..._)와 같다
    map(p => p.price)
    reduce(add, prices),
    console.log);


합수 조합으로 함수 만들기

중복되는 함수들을 또 하나의 함수로 만들어 효율적으로 사용할 수 있다.

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

const totalPrice = pipe(
	map(p => p.price,
  reduce(add, prices)
) 

const baseTotalPrice = predi => pipe(
	filter(predi), 
  totalPrice,
)

go(
    products,          
    baseTotalPrice(p => p.price < 20000), 
    console.log);

go(
    products,          
    baseTotalPrice(p => p.price >= 20000), 
    console.log);

기존 함수들을 조합해 새로운 함수로 만들 때,

기존 함수를 그대로 사용하고 싶으면
→ 변수에 그대로 넣어서 사용한다.

기쫀 함수를 바꿔서 사용하고 싶으면
→ 해당 함수를 리턴하는 새로운 함수를 만들어서 할당하는데, 인자를 받아서 그 인자로 리턴하는 함수를 조작한다.


강의를 듣는 초반에는 쉽다고 생각했는데 뒤로 갈수록 뇌에 혼란이 왔다.
go, pipe도 그렇지만 특히 curry...

함수형 프로그래밍이 볼 때는 간략하고 쉬워보이지만 그렇게 만들기 위한 과정이 굉장히 어렵고 복잡하다는 것을 느꼈다.

1주차 과제를 풀 때 자료구조에 대해 완전히 이해하지 못했어서 결과가 만족스럽지 못했기 때문에, 2주차 때에는 개념과 원리를 완벽히 이해하고 과제를 구현하고 싶었다. 하지만 모든 걸 다 이해하고 넘어가려다보니 시간이 너무 소요됐다.
과제 기한이 정해져있기 때문에 어느 정도 융통성있게 학습하면서 시간 관리를
해야겠다는 생각이 들었다.

profile
#프론트엔드

0개의 댓글