제때 계산법, 느긋한 계산법으로 연산을 미룰 수 있을 때까지 미루었다가 필요한 시점에 값을 만들어 계산하는 것으로 굉장히 영리한 평가 방법이다.
지연평가는 제너레이터/이터레이터 프로토콜을 기반으로 구현되어야 한다.
L.map = function *(f, iter) {
for (const a of iter){
yield f(a)
}
}
const it = L.map((a) => a+1, [0,1,2,3,4])
log(...it) /// 1 2 3 4 5
L.filter = function*(f, iter){
for (const a of iter){
if (f(a)) {
yield a;
}
}
}
const fi = L.filter((v) => v%2, [1,2,3,4,5,6])
log(...fi) // 1 3 5
L.map = curry(function *(f, iter) {
for (const a of iter){
yield f(a)
}
})
L.filter = curry(function*(f, iter){
for (const a of iter){
if (f(a)) {
yield a;
}
}
})
curry를 적용해서 리턴되는 함수의 인자가 맞춰질때까지 기다렸다가 실행되도록 했다.
go(
L.range(10000),
L.filter((v) => v %2),
L.map((v) => v + 10),
take(3),
reduce(add),
log
) /// 200
go(
L.range(10000),
L.map((v) => v + 10),
L.filter((v) => v %2),
take(3),
reduce(add),
log
) /// 200
이렇게 지연평가가 적용된 함수를 작성하게 되면 이터러블을 처음부터 만들어 놓고 시작하는 것이 아니기때문에 어떤 순서로 결합을 하던 같은 결과가 출력된다.
const L.entries = function*(obj){
for (const a in obj){
yield [a, obj[a]];
}
}
const join = curry((sep=",", iter) => {
return reduce((a,b)=> ${a}${sep}${b} ,iter)
})
const queryStr = pipe(
L.entries(obj),
L.map([k,v] => ${k}=${v}),
join('&'))
log(queryStr({ limit: 10, offset: 10, type: 'notice' }));
const users = [
{ age: 32 },
{ age: 31 },
{ age: 37 },
{ age: 28 },
{ age: 25 },
{ age: 32 },
{ age: 31 },
{ age: 37 }
]
const find = curry((f,iter) => {
return go(iter,
L.filter(f),
take(1),
([v]) => v)
})
console.log(find((users) => users.age < 30)(users))
// {age: 28}
go(
users,
find((user) => user.age < 30),
console.log
)
// // {age: 28}