[TIL] day07. 고차함수와 go,pipe,curry

kcm dev blog·2021년 8월 10일
0

TIL

목록 보기
5/19
post-thumbnail

Intro

오늘 아침까지만해도 일정상으로는 강의 외에는 특별한 일정이 없었기 때문에 조금은 여유롭게 일정을 소화하고 저녁에는 휴식을 취할수 있을 줄 았았다. 고차함수를 배울때까지만 해도 그럴줄 알았다. 어제 배운 iterable protocol에서 특이한 문법(computed property name)과 iterable, iterator의 정확한 차이를 정확히 모른 상태로 넘어가서 그 내용들을 집고 넘어가느라 시간이 좀더 지체되긴 했지만 그래도 크게 영향은 없겠거니 했다.

근데... go, pipe, curry 라는 개념을 들어가면서 분위기가 사악 바뀌었다. 이해도 안가는게 구글링을 해봐도 같은 강사님한테 들은 분들의 블로그 포스팅 정도 보이고, MDN이나 개념서적 인덱스에도 안나오는 개념이었다. 반복적으로 듣고, 예시 코드를 쳐보면서 어느정도 이게 뭐구나 정도 알았는데, html파일에 script를 적용하는 예제에서 알수 없는 이유로 콘솔에 출력은 되는데 객체 값이 안나오고 undefined만 나오는 일이 계속 되었다. 2시간 넘게 고민하다 단톡방에 올려서, 다른 분의 소스코드를 받아서 1:1 비교 작업에 들어갔다.

1시간의 탐색 끝에... 에로우 함수에서 1줄안에 쓰면 { }return을 생략할 수 있는 문법이 있는데 { }를 써놓고 return을 안쓰는 실수가 2시간의 대참사를 만들어 내었다. 그거 하나 때문에 11시 넘어서 강의를 간신히 끝마쳤다. 오늘 경험덕에 비슷한 실수는 절대 안할것 같다. 그리고.. 집단지성은 문제해결에 상당한 도움이 되었다. 직접적인 도움이 되지 않았지만, 문제의 원인을 찾아야 한다는 압박감(?) 내지 책임감이 있었고, 같이 고민해 주신분들에게 해결책을 알려줘야 한다는 의무감이 꽤나 크게 작용했다. 함께 공부하고 있어서 행복한 날이었다

오늘 배운 개념

  • Map
  • Filter
  • Reduce
  • Map, Filter, Reduce 중첩하여 사용하기
    • go
    • pipe
    • curry

Iterator & Iterable

  • iterable: 아래 규칙들을 따르는 순회 가능한 객체

    1. "well known" symobl인 Symbol.iterator를 메소드로 가져야 한다
    2. 순회 가능한 데이터를 가지고 있어야 한다
    3. Symbol.iterator는 'iterator'객체를 리턴해야 한다
    4. 'iterator'객체는 next() 메소드를 갖는다
    5. next()를 통해 '순회가능한 데이터'에 접근 가능해야 한다
    6. next를 호출하면 {value:<stored data},done:false}가 추쵤되야 하고
      전부 순회시 {done:false}가 리턴되야 한다

    이러한 규칙들을 모두 따르는 것을 iterable이라고 하며, 리턴된 객체를 iterator라고 한다.
    참고링크

예시

const iterable={
  [Symbol.iterator](){
    let i=3;
    return{
      next(){
        return i==0?{done:true}:{value:i--,done:false};
      },
      [Symbol.iterator](){return this;}
    }
  }
};


let iterator=iterable[Symbol.iterator]();

go

인자로 함수들을 받아 차례대로 실행시켜 결과에 해당하는 값을 리턴하는 함수

원리는 1번째 파라미터시작값이고, 이후 n번째 파리미터(메소드)1번째 파리미터의 값을 대입하여 값을 리턴한다.그리고 n+1번째 파라미터(메소드)가 리턴한 값을 받아 실행한다.

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

const g=(para)=>go(para,
    a=>a+1,
    a=>a+10,
    a=>a+100,
)
console.log(g(0));//111

해당 함수의 장점은 가독성에 있다. 고차함수를 연속적으로 사용하면, 결과값을 알기 위해서는 in->out 방식으로 값을 추적해야 한다. 하지만 go를 씀으로써 top->down 방향으로 결과값을 추적할 수 있다. 코드량이 좀 늘어나기는 하지만 가독성 측면에서 더 좋기 때문에 사용하는 함수라고 할 수 있다.

pipe

함수를 리턴하는 함수

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));

n번째 파리미터(메소드)가 리턴한 값을 n+1번째 파라미터(메소드)가 값을 받아 실행하는 방식이다. Go를 약간 변형시키면 pipe로 변환도 가능하다.

const g=(para)=>go(para,
    a=>a+1,
    a=>a+10,
    a=>a+100,
);
//변환하면...
const p=pipe(
  a=>a+1,
  a=>a+10,
  a=>1+100
);
console.log(p(0));

curry

함수를 값으로 다루면서 받아둔 함수를 내가 원하는 시점에 평가 가능

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

const mult=curry((a,b)=>a*b);
console.log(mult(3)(2));

const mult3=mult(3);
console.log(mult3(10));//30
console.log(mult3(5));//15
console.log(mult3(3));//9

하루를 마무리 하며

Map, Filter, Reduce는 이미 알고 있는 개념이었지만, 함수형 프로그래밍보다는 객체지향 프로그래밍 방식이 더 익숙한터라 해당 메소드를 자주 이용하는 편은 아니었다. 그러나 이 고차함수이야 말로 JS의 아이덴티티 같다는 생각이 들었다. iteratable protocol에 따라 정의된 개념이고, 여기서 파생된 개념들의 양이 상당했다

오늘 하루만에 모든걸 소화하긴 어렵지만 다른걸 몰라도 iterable protocol에 대한 개념은 제대로 파악하고 넘아가야 겠다. 오늘의 핵심은 사실 go, pipe,curry이지만.. 사실 아직까지 그렇게 필요성이 높은지는 아직까진 모르겠다 사실..

profile
오늘 배운건 오늘 소화하자!

0개의 댓글