[JS] 지연성

최정환·2021년 9월 27일
0

go curry pipe

range

🔧 reduce에 담기기전 list의 상태는 배열이다

const add = (a,b) => a+b;

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

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

var list = range(4);
log(list);	// [0,1,2,3]
log(reduce(add ,list))	// 6

🔧 while안 log(i,'range'); 결과

0"range"
1"range"
2"range"
3"range"



느긋한 L.range

🔧 배열을 만들지 않고 제너레이터를 이용해 생성하고 리턴한다.

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

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

var list = range(4);
log(list);	// L.range {}
log(reduce(add ,list))	// 6

🔧 while안 log(i,'L.range'); 결과 실행되지 않는다.
list.next()가 실행되기 전까진 어떠한 코드도 동작하지 않는다.
log(list.next()); 를 한다면

0'L.range'	{value:0,done:false}
1'L.range'	{value:1,done:false}
...



range와 L.range 테스트

🔧

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

test('L.range',10,()=>reduce(add, L.range(100000))); // L.range:257.204833..
test('range',10,()=>reduce(add, range(100000))); // range:489.6808..



take

🔧 L.range 같이 지연성을 가지는 값을 iterator로 만들게 되면 전혀 다른 take와 같은 함수가 iterator 프로토콜만 따른다면 소통이 가능하다.

take(5, L.range(10000))에서 10000의 array를 만들지 않고 5개의 값만 만들기 떄문에 10000개의 index를 가진 array를 만들어 내는 range(10000) 보다 빠르다.

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

log(range(100)); // [0,1,2....,99]
log(take(5, L.range(100)); // [0,1,2,3,4]
go(L.range(10000),take(5),log);	// [0,1,2,3,4]



이터러블 중심 프로그래밍에서의 지연 평가 (Lazy Evaluation)

  • 제때 계산법
  • 느긋한 계산법
  • 제너레이터/이터레이터 프로토콜을 기반으로 구현



L.map

🔧

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

🔧 for of문을 while문으로 표현

L.map = function *(f, iter) {
  	let res = [];
	iter = iter[Symbol.iterator]();
  	let cur;
  while(!(cur = iter.next()).done){
  	const a = cur.value;
    res.push(f(a))
  }
};

L.filter

🔧 f(a) true시 반환 즉, 1일때 a%2 는 홀수 즉 나머지가 1인 값을 찾음

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



range, map, filter, take, reduce 중첩 사용

🔧

0개의 댓글