함수형 프로그래밍 - 지연 평가(1)

jiseong·2022년 7월 5일
0

T I Learned

목록 보기
284/291

지연평가는 계산의 결과 값이 필요할 때까지 계산을 늦추는 기법으로 필요한 경우에 도달할 때까지 계산을 늦추기 때문에 불필요한 계산을 줄일 수 있다는 장점이 있다.

해당 부분을 학습하면서 take함수로 인해 지연평가가 주는 장점이 확 와닿았기 때문에 그 부분을 작성해보았다.

range, take

우선 take 함수의 코드를 확인하기전에 range함수를 먼저 알아보자.

range함수는 지정한 범위만큼 배열의 요소를 생성하는 함수로 테스트를 위해서 즉시평가하는 함수와 지연평가하는 함수 두가지 버전을 만들었다.

range

첫번째 range함수는 즉시평가하기 때문에 0~ 3까지 범위 값을 배열의 요소로 즉시 만든 후 동작하게 된다.

const range = (l) => {
  let i = -1;
  const res = [];
  while(++i < l){
    res.push(i);
  }
  return res;
}

const list1 = range(4); // [0, 1, 2, 3]
console.log(reduce(add, list1)); // 6

두번째 range함수는 지연평가를 하기 때문에 array를 만들지 않고 하나씩 값을 평가하여 동작하게 된다.

const L = {};
L.range = function *(l) {
  let i = -1;
  while(++i < l) {
    yield i;
  }
}

const list2 = L.range(4); // 제네레이터 함수를 실행했기 때문에 제네레이터 객체가 반환되었을 뿐 배열이 만들어지지 않았다.
console.log(list2); // 아직 평가가 안됨.
// iterator 내부에서 순회할때 마다 하나씩 평가 // list.next();
console.log(reduce(add, list2)); // 6

take

take함수는 지정한 갯수만큼 앞에서부터 뽑아내어 배열로 반환하는 함수이다.

// 지정한 갯수만큼 앞에서부터 뽑아내어 배열로 반환하는 함수
const take = (l, iter) => {
  let res = [];
  for(const a of iter) {
    res.push(a);
    if(res.length === l) return res;
  }
  return res;
}

이제 take함수와 range 함수를 조합하여 테스트를 해보면 다음과 같은 결과를 확인할 수 있는데 여기서 지연평가를 하는 함수는 실제로 순회할때마다 값을 하나씩 평가하기 때문에 범위가 커졌을 때 불필요한 계산을 줄임으로써 기존의 함수와 속도가 확연하게 차이나게 된 것이다.

// 1000000 범위의 크기를 가진 배열의 요소들 중에서 
// 앞부분부터 시작하여 5개의 요소를 가져오는 함수를 10번 실행시키는 코드이다.
test('range', 10, () => take(5, range(1000000)));
test('L.range', 10, () => take(5, L.range(1000000)));

이전 포스팅에서 작성했던 go, map, filter, curry함수를 함께 사용하여 지연평가를 해보아도 얼마나 효율적으로 값을 평가하는지 확인할 수 있었다.

breakpoint를 적용하여 평가순서를 확인해보면 많은 도움이 된다.

// 즉시평가를 이용한 예시
go(range(10), // [0, 1, 2, 3, ...9]
  map(n => n + 10), // [10, 11, 12, 13, ...19]
  filter(n => n % 2), // [11, 13, 15, 17, 19]
  take(2), // [11, 13]
  console.log);

// 지연평가를 이용한 예시
go(L.range(10),          // 0  1  2  3
  L.map(n => n + 10),    // 10 11 12 13
  L.filter(n => n % 2),  //    11    13
  take(2),               //    11    13 종료 (위에서 아래로 흐름)
  console.log);

Reference

0개의 댓글