[JavaScript ES6+] 지연성 1

Yujin Lee·2021년 5월 7일
0

JavaScript

목록 보기
12/14
post-thumbnail

1. range와 느긋한 L.range

1) 지연 평가

컴퓨터 프로그래밍에서 느긋한 계산법(Lazy evaluation)은 계산의 결과 값이 필요할 때까지 계산을 늦추는 기법이다. 지연 평가를 하면 필요 할 때까지 계산을 늦추면서 불필요한 계산을 줄일 수 있다.

이점

  1. 불필요한 계산을 하지 않으므로 빠른 계산이 가능하다.
  2. 무한 자료 구조를 사용 할 수 있다.
  3. 복잡한 수식에서 오류 상태를 피할 수 있다.

2) range

reduce에 list를 전달하기 전에 이미 range를 실행했을 때 이 list라는 변수에 담긴 값이 배열인 상태

숫자하나를 받고 그 숫자의 크기만한 배열을 리턴 후에 그 값들을 더하는 range함수를 선언한다.

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

결과

log(range(5));
// [0, 1, 2, 3, 4]
log(range(2));
// [0, 1]

range


3) 느긋한 L.range

L.range에서의 list의 값은 이터레이터이다.

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

결과

var list = L.range(4);
log(list); //뭔가 특이한게 출력됨 => 이터레이터임!
log(reduce(add, list));

L.range



range 와 L.range 둘다 같은 결과인 6을 출력했지만 그 결과가 다르다.

동작 비교

  • range: array를 만듦→ 이터레이터를 만듦 → next를 만들면서 순회
  • L.range: array를 만들지 않고 실행될때 이터레이터를 만듦 → 그 이터레이터가 자기 자신을 리턴하는 이터러블이 됨 → 해당 함수를 실행하면 이미 만들어진 이터레이터를 그냥 리턴만하고 순회

4) range와 L.range의 효율성 비교

function test(name, time, f) {
    console.time(name);
    while (time--) f();
    console.timeEnd(name);
}

test('range', 10, () => reduce(add, range(1000000)));
test('L.range', 10, () => reduce(add, L.range(1000000)));

range에 비해 L.range가 시간 효율이 높음을 확인할 수 있다.


2. take

take 함수는 값을 받아서, 원하는 크기 만큼 잘라주는 함수이다.

const take = curry((l, iter) => {
    let res = [];
    for (const a of iter) { //받은 이터러블 순회
        res.push(a); //결과에 push
        if (res.length == l) return res;
        //결과를 담고있는 결과의 length와 리미트가 같아지면 그만 순회
    }
    return res;
});

log(take(5, range(100)));
log(take(5, L.range(100)));


결과는 동일하나 속도를 확인해보면 차이가 있다.

console.time('');
log(take(5, range(100)));
console.timeEnd('');

console.time('');
log(take(5, L.range(100)));
console.timeEnd('');




3. L.map

L.map은 새로운 Array를 만들지 않고, 이터러블을 순회하면서,
각 요소에 대해 함수를 적용한 값을 yield를 통해 게으른 평가를 수행한다.

평가를 미루는 성질을 가지고 평가 순서를 달리 조작할 준비가 되어있는 이터레이터를 반환하는 제너레이터

L.map = function *(f, iter) {
    for (const a of iter) yield f(a); // f(a)
};
var it = L.map(a => a + 10, [1, 2, 3]);
log(it.next());
log(it.next());
log(it.next());

L.map




4. L.filter

L.filter는 이터러블을 순회하면서, 조건결과 값이 참인 경우에만 값을 yield를 통해 발생시킨다.

L.filter = function *(f, iter) {
    for (const a of iter) if (f(a)) yield a; // a
};
var it = L.filter(a => a % 2, [1, 2, 3, 4]);
log(it.next());
log(it.next());
log(it.next());

L.filter




5. map, filter 계열 함수들이 가지는 결합 법칙

  • 사용하는 데이터가 무엇이든지
    사용하는 보조 함수가 순수 함수라면 무엇이든지
    아래와 같이 결합한다면 둘 다 결과가 같다.
[[mapping, mapping], [filtering, filtering], [mapping, mapping]]
=
[[mapping, filtering, mapping], [mapping, filtering, mapping]]
profile
I can be your Genie🧞‍♀️ How ‘bout Aladdin? 🧞‍♂️

0개의 댓글