본문 바로가기
JavaScript

[FP&ES6+] 결과를 만드는 함수 - take

by _sweep 2021. 12. 27.

함수형 프로그래밍과 JavaScript ES6+ 강의를 듣고 정리한 내용입니다.

 

 

결과를 만드는 함수

map과 filter는 이터러블 안쪽의 값을 꺼내서 기본적인 값을 유지한 채로 새로운 값을 만든다.

반대로 reduce take는 이터러블 안쪽의 값을 꺼내는 것은 동일하나 값을 유지시키는 것이 아닌 연산이나 특정 방식으로 값을 깨뜨려 그 결과가 합쳐진 새로운 값을 만들어낸다.

즉, 결과를 만들어 낸다.

 

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

const take = curry((limit, iter) => {
  let res = [];
  for (const a of iter) {
    res.push(a);
    if (res.length == limit) return res;
  }
  return res;
});

 

 

 

✏️ 예제 - find()

take 함수를 활용한 예제로 find 함수를 만들어보자.

 

## 함수 설명

find 함수는 주어진 조건에 해당하는 값을 찾는데 이때 제일 먼저 찾은 값을 리턴한다.

즉, 특정 값 하나만 찾는다.

 

 

## 함수 구현

const find = (f, iter) => go(
    iter,
    filter(f),
    take(1)
);

 

조건이 될 함수 f와 이터러블인 iter를 인자로 받는다.

go문 안에서 iter가 filter부터 순서대로 넘어간다.

filter로 주어진 조건 f에 해당하는 a들을 찾은 후 take로 값 하나만 꺼낸다.

 

 

const users = [
    { age: 25 },
    { age: 20 },
    { age: 37 },
    { age: 15 },
    { age: 28 }
];

const find = (f, iter) => go(
    iter,
    filter(f),
    take(1),
    ([a]) => a // 배열이 아닌 객체 리턴
);

console.log(find(u => u.age < 25, users));

// output
// {age: 20}

 

users라는 객체가 담긴 배열이 주어졌다.

이때 age가 25 미만인 user 하나를 찾고자 할 때 find 함수는 위와 같이 구현할 수 있다.

find 함수의 기본 구현과 일치하지만 리턴 시 배열이 아닌 객체를 리턴하기 위해 구조를 분해하는 과정만 추가했다.

 

위와 같이 find를 구현했을 때는 주어진 iter의 요소들을 모두 살펴보고 조건에 해당하는지를 판별한다.

판별을 모두 마치면 주어진 조건에 해당하는 iter의 요소들만 남게되는데 이때 그 값 중 첫 번째에 있는 값을 꺼내 리턴한다.

 

이 과정을 보면 조건에 해당하는 제일 첫 번째 값이 필요한데

그 값을 찾았음에도 불구하고 iter의 요소들을 모두 살펴보는 불필요한 과정을 거치고 있음을 알 수 있다.

 

 

const find = (f, iter) => go(
    iter,
    L.filter(f),
    take(1),
    ([a]) => a
);

console.log(find(u => u.age < 25, users));

// output
// {age: 20}

 

따라서 filter 대신 지연 평가를 하는 L.filter를 사용하면 불필요한 과정을 줄일 수 있다.

L.filter를 사용했을 때는 평가가 필요한 시점인 take부터 시작한다.

take에서 평가할 값 하나가 필요할 때 미뤄두었던 평가가 시작되고 iter를 살펴보다 조건에 해당하는 값을 처음 만났을 때 즉시 take에게 넘겨준다.

 

 

const find = curry((f, iter) => go(
    iter,
    L.filter(f),
    take(1),
    ([a]) => a
));

console.log(find(u => u.age < 25)(users));

// output
// {age: 20}
go(
    users,
    L.map(u => u.age),
    find(n => n < 30),
    console.log
);

// output
// 25

 

결국 find는 take를 통해 이터러블을 받는다.

즉, find도 이터러블 프로토콜을 따르기 때문에 위와 같은 구현도 가능하다.

 

 

 

 

 

댓글