/* eslint-disable */
import { log, curry, map, filter, reduce, go, pipe } from '../lib/fx.js';
/* 지연평가 */
const add = (a, b) => a + b;
// range
const range = l => {
let i = -1;
let result = [];
while (++i < l) {
log(i, 'range');
result.push(i);
}
return result;
}
var list = range(4); // range를 호출했을 때, 즉시 배열로 평가된다.
log(list); // [0, 1, 2, 3, 4]
log(reduce(add, list)); //6
// 느긋한 L.range
const L = {};
L.range = function* (l) {
let i = -1;
while (++i < l) {
log(i, 'L.range');
yield i;
}
}
var list = L.range(4); // range를 호출했을 때, 아직 평가되지 않는다.
log(list); // L.range : Generator
log(reduce(add, list)); // array를 만들지 않고, 하나씩 값을 꺼내게 된다.
const test = (name, time, f) => {
console.time(name);
while (time--) f();
console.timeEnd(name);
}
test('L.range', 1, () => reduce(add, L.range(10000000))); // 200ms
test('range', 1, () => reduce(add, range(10000000))); // 250ms
const take = curry((l, iter) => {
let res = [];
for (const a of iter) {
res.push(a);
if (res.length == l) return res;
}
return res;
})
console.time('기본');
go(
range(10000),
take(5), // 5개만 꺼내온다.
reduce(add),
log
)
console.timeEnd('기본');
console.time('지연');
go(
L.range(10000),
take(5), // 5개만 꺼내온다.
reduce(add),
log
)
L.range = function* (l) {
let i = -1;
while (++i < l) {
yield i;
}
}
L.map = function* (f, iter) {
for (const a of iter) yield f(a);
}
const takeAll = take(Infinity);
export const map = curry(pipe(L.map, takeAll));
export const filter = curry(pipe(L.filter, takeAll));
이는 결국 결과를 만드는 take에 의해 이터레이터가 평가되면서 원래의 map, filter과 같은 동작을 하게 된다.
L.flatten = function* (iter) {
for (const a of iter) {
if (isIterable(a)) yield* a
else yield a;
}
}
export const flatten = curry(pipe(L.flatten, takeAll));
L.deepflat = function* f(iter) {
for (const a of iter) {
if (isIterable(a)) yield* f(a)
else yield a;
}
}
L.flatMap = curry(pipe(L.map, L.flatten));
export const flatMap = curry(pipe(L.map, flatten));
export const join = curry((sep = ',', iter) =>
reduce((a, b) => `${a}${sep}${b}`, iter));