결론★
1.Iterable은 순환이 가능한 값이다.
2.Iterable은 Iterator를 리턴하는 [Symbol.interator]() 함수를 가진다.
3.Iterator는 { value:값, done: bool값 }형태 객체를 리턴하는 next()함수를 가진다.
4.Iterable은 for...of, 전개 연산자, 구조분해, 나머지 연산자 등과 함께 사용할 수 있다. ex) for...of는 next() done:true가 될 때까지 순환한다.
5.Generator는 Iterable이자 Iterable을 생성하는 함수이다. 함수명에 *를 붙여 선언한다.
6. Generator에서 순회할 값 앞에 yield 키워드를 붙여준다. 그럼 이터레이터가 next()로 단계적 순회하듯, 제어가 가능하다. (for문 처럼 한 번에 와라락 순환하는게 아니라 요소 하나하나를 단계적으로 접근해서 순환한다. 예제 코드3 참조)
7.Generator에서 리턴 값은 순회할 때 출력되지 않는다. 6번에서 말했든 yield 키워드가 붙은 것만 순회함.
예제 코드1
const array1 = [1,2,3,4,5,6];
let iter1 = array1[Symbol.iterator]();
console.log(iter1.next()); // {value:1, doen:false}
console.log(iter1.next()); // {value:2, doen:false}
console.log(iter1.next()); // {value:3, doen:false}
console.log(iter1.next()); // {value:4, doen:false}
console.log(iter1.next()); // {value:5, doen:false}
console.log(iter1.next()); // {value:6, doen:false}
console.log(iter1.next()); // {value:undefined, doen:true} -> array1에대한 순환이 끝남
예제1 출력을 보면 next()는 이전에 실행했던 지점을 기억해 두었다가 다음 호출엔 그 다음 값을 가져온다.
next()가 반환하는 객체에서 value 속성엔 이터러블 요소의 값이 담기고, done 속성에는 순환이 끝났는지 여부가 bool값으로 담긴다.
즉, Iterator를 사용하면 순환/반복 처리를 단계별로 제어할 수 있다.
예제 코드2
function *gener(){
yield 'a';
yield 'b';
yield 'c';
return 'The end!';
}
let iter2 = gener(); //iter2는 이터러블이자 이터레이터
console.log(iter2.next()); // {value:'a', doen:false}
console.log(iter2.next()); // {value:'b', doen:false}
console.log(iter2.next()); // {value:'c', doen:false}
console.log(iter2.next()); // {value:'The end', doen:true} -> 순환 끝
제너레이터 생성 및 출력 결과이다.
예제 코드3
//매표기기
function *machine(limit, makeTicket_iter){
for(const ticket of makeTicket_iter){
yield ticket
if(ticket === limit) return;
}
}
//티켓 생성기기
function *makeTicket(i = 0){
while(true){
yield i++;
}
}
//발권 기계
function *ticketingMachine(l) {
for(const a of machine(l, makeTicket(1))){
yield a
if(a === l ) return 'Sold Out'
}
}
// 총 10개까지 티켓을 살 수 있는 기계
const ticketingMachine10 = ticketingMachine(10);
console.log(ticketingMachine10.next());
console.log(ticketingMachine10.next());
console.log(ticketingMachine10.next());
console.log(ticketingMachine10.next());
console.log(ticketingMachine10.next());
console.log(ticketingMachine10.next());
console.log(ticketingMachine10.next());
console.log(ticketingMachine10.next());
console.log(ticketingMachine10.next());
console.log(ticketingMachine10.next());
console.log(ticketingMachine10.next());
console.log(ticketingMachine10.next());
makeTicket 제너레이터의 경우, while문이 무한 루프이지만, yield 키워드를 사용함으로써 next()함수가를 통해 평가되기 전까진 다음 단계로 넘어가지 않기 때문에 일반적인 무한 루프문과는 달리 시스템에 부하를 주지 않고 무한대의 수를 만들어 낼 수 있다.
예제 코드4
그 외 for...of, 구조분해, 전개연산자,나머지 연산자와도 함께 사용될 수 있다.
//매표기기
function *machine(limit, makeTicket_iter){
for(const ticket of makeTicket_iter){
yield ticket
if(ticket === limit) return;
}
}
//티켓 생성기기
function *makeTicket(i = 0){
while(true){
yield i++;
}
}
// 홀수표 발권 기계
function *ticketingMachine(l) {
for(const a of machine(l, makeTicket(1))){
if(a % 2 ) yield a
}
}
//15까지의 홀수표 발권기
const ticketingMachine15 = ticketingMachine(15);
//15까지의 홀수표를 펼쳐서 보여준다
console.log(...ticketingMachine(10)); // 1 2 3 4 5 6 7 8 9 10
const [first1, ...middle1] = ticketingMachine(15);
console.log(first1, middle1);
const [first2, middle2, ...rest] = ticketingMachine(15);
console.log(first2, middle2, rest);
이런 이터러블이 있다고 치자.
const products = [
{name:'검정후드', price:20000, quantity:1},
{name:'팔찌', price:7000, quantity:2},
{name:'지우개', price:1000, quantity:3},
{name:'폰케이스', price:5000, quantity:4},
{name:'썬글라스', price:18000, quantity:5},
{name:'키보드', price:28000, quantity:2},
];
const curry = f => (a, ..._) => _.length ? f(a, ..._) : (..._) => f(a, ..._);
const map = curry((f, iter) => {
let res = [];
for (const elem of iter) res.push(f(elem));
return res;
});
const filter = curry((f, values) => {
let res = [];
for(const elem of values) if(f(elem)) res.push(elem);
return res;
});
const reduce = curry((f, acc ,iter) => {
if(!iter){
iter = acc[Symbol.iterator]();
acc = iter.next().value;
}
for(const elem of iter) {
acc = f(acc,elem);
}
return acc;
});
const go = (...args) => {
return reduce((a,f) => f(a), args);
}
const pipe = (f, ...fs) => (...as) => go(f(...as), ...fs);
const totalPrice = go(
products,
map(elem => elem.price),
filter( elem => elem >= 20000),
reduce((a,b) => a+b)
)
const f = pipe(
(a, b) => a + b,
a => a + 10,
a => a + 100);
const amount = pipe(
map(elem => elem.quantity),
reduce((a,b) => a+b));
console.log(amount(products));
'Web > 유인동 함수형 프로그래밍 스터디' 카테고리의 다른 글
함수형 프로그래밍 시작하기 (0) | 2020.11.26 |
---|