JavaScript/함수형 프로그래밍과 JavaScript ES6+

odds(제너레이터와 이터레이터) & for of etc..

느리지만 꾸준하게 2021. 8. 17. 18:51

제너레이터를 활용해서 홀수만 계속해서 발생시키는 그러한 이터레이터를 만들어서 순회하는 예제를 작성한다.

우선 제너레이터 함수가 있다고 하자. 1 3 5 홀수만 생성한다.

<script>
    function* odds() {
        yield 1;
        yield 3;
        yield 5;
    }
    let iter2 = odds();
    log(iter2.next());
    log(iter2.next());
    log(iter2.next());
    log(iter2.next());
</script>

=>

{value: 1, done: false}
{value: 3, done: false}
{value: 5, done: false}
{value: undefined, done: true}

위에 코드는 직접 입력을 해줘야만 계속해서 홀수를 생성할 수 있는데 좀더 자동화해서 만들어보면 limit값을 받고 해당하는 값을 받아서 최대 10보다 작은 홀수까지만 출력하는 제너레이터를 작성할 수 있다.

<script>
    function* odds(l) {
        for (let i = 0; i < l; i++) {
            if (i % 2) yield i;
        }
    }
    let iter2 = odds(10);
    log(iter2.next());
    log(iter2.next());
    log(iter2.next());
    log(iter2.next());
    log(iter2.next());
    log(iter2.next());
    log(iter2.next());
    log(iter2.next());
</script>



=>

{value: 1, done: false}
{value: 3, done: false}
{value: 5, done: false}
{value: 7, done: false}
{value: 9, done: false}
{value: undefined, done: true}
{value: undefined, done: true}
{value: undefined, done: true}

더 많은 제너레이터를 함께 사용하면서 만들어보자. infinity 제너레이터를 만들어보면 0부터 시작해서 혹은 넘겨준 값으로 부터 시작해서 무한히 i++하면서 해당하는 값을 계속해서 리턴한다고 가정해본다. infinity라는 제너레이터가 있으면 제너레이터를 통해서 생성하는 이터레이터는 next를 할 때마다 계속해서 생성할 것이다.

무한히 값을 생성하지만 사용자가 이터레이터의 next를 평가할 때 까지만 동작하기 때문에 while true인 코드를 작성한다고 해서 브라우저가 멈추거나 프로그램이 멈추는 일은 없다.

 

이런식으로 무한수열을 표현할 수 있다.

    function *infinity(i = 0) {
        while (true) yield i++;
    }
let iter3 = infinity();
undefined

iter3.next()
{value: 0, done: false}

iter3.next()
{value: 1, done: false}

iter3.next()
{value: 2, done: false}

iter3.next()
{value: 3, done: false}

iter3.next()
{value: 4, done: false}

iter3.next()
{value: 5, done: false}

iter3.next()
{value: 6, done: false}

iter3.next()
{value: 7, done: false}

iter3.next()
{value: 8, done: false}

무한수열을 통해서 홀수만 뽑는 함수를 변형해보자. 아래와 같이 코드를 작성해도 정상적으로 작동한다. 

    function* infinity(i = 0) {
        while (true) yield i++;
    }
    function* odds(l) {
        for (const a of infinity(1)) {
            if (a % 2) yield a;
            if (a == l) return;
        }
    }
 
 
=>

{value: 1, done: false}
{value: 3, done: false}
{value: 5, done: false}
{value: 7, done: false}
{value: 9, done: false}
{value: undefined, done: true}
{value: undefined, done: true}
{value: undefined, done: true}

좀 더 변화를 주면 이번에는 limit을 만드는 제너레이터를 만들어서 l과 iter을 받도록 하자.

이 함수는 이터러블을 받아서 계속해서 이터러블 안에 있는 값을 yield하다가 받아둔 l과 같은 값을 만나면 더이상 돌지 않도록 동작할 것이다.

<script>
    function* infinity(i = 0) {
        while (true) yield i++;
    }

    function* limit(l, iter) {
        for (const a of iter) {
            yield a;
            if (a == l) return;
        }
    }

    function* odds(l) {
        for (const a of limit(l, infinity(1))) {
            if (a % 2) yield a;
        }
    }

    let iter2 = odds(10);
    log(iter2.next());
    log(iter2.next());
    log(iter2.next());
    log(iter2.next());
    log(iter2.next());
    log(iter2.next());
    log(iter2.next());

    for (const a of odds(40)) log(a);

    console.clear();
</script>

 

for...of, 전개 연산자, 구조 분해, 나머지 연산자

제너레이터는 이터러블 이터레이터 프로토콜을 따르고 있기 때문에

for of문이나 전개 연산자 구조 분해 나머지 연산자 등 자바스크립트에서 이터러블 프로토콜을 따르고 있는 문법들 혹은 이터러블 프로토콜을 따르고 있는 많은 라이브러리나 많은 함수들 헬퍼함수들과 함께 잘 사용될 수가 있다.

 

아래와 같이 코드를 작성할 수 있다. const [head, ...tail]과 같이 구조분해를 통해서도 사용할 수 있다.

자바스크립트에서는 이터러블 이터레이터 프로토콜을 가지고 활용할 수 있는 문법들과 기능들이 굉장히 많고 잘 동작하고 있다. 많은 라이브러리들이나 함수들도 이터러블 프로토콜을 따르도록 구성이 되어있다면 이렇게 제너레이터나 이터레이터등을 활용을 잘할때 좀 더 조합성이 높은 프로그래밍을 할 수 있다. 

 

제너레이터와 이터러블과 이터레이터등을 많이 활용하여서 함수형 프로그래밍 관점에서 이것들을 해석해서 학습해보자. 

<script>
	log(...odds(10));
	log([...odds(10), ...odds(20)]);

	const [head, ...tail] = odds(5);
	log(head);
	log(tail);

	const [a, b, ...rest] = odds(10);
	log(a);
	log(b);
	log(rest);
</script>


=>


1 3 5 7 9
[1, 3, 5, 7, 9, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
1
[3, 5]
1
3
(3) [5, 7, 9]

 

 

 

<출처 : 유인동 함수형 프로그래밍과 JavaScript ES6+>

https://www.inflearn.com/course/functional-es6/dashboard

 

함수형 프로그래밍과 JavaScript ES6+ - 인프런 | 강의

ES6+와 함수형 프로그래밍을 배울 수 있는 강의입니다. 이 강좌에서는 ES6+의 이터러블/이터레이터/제너레이터 프로토콜을 상세히 다루고 응용합니다. 이터러블을 기반으로한 함수형 프로그래밍,

www.inflearn.com