02.07 TIL
25960 ワード
私は関数プログラミングとJavaScript ES 6+を勉強しています.
また,PromiseはPromiseであるが,条件を満たさない値は後で伝達されない.拒否(nop)を使用しました.
これでtake関数からfilter処理の拒否値を受信すれば終了する.
PromiseはKleisli Componentの観点から、拒否された値は後のthenを無視してcatchに移動するため、L.filterの後に他の関数があっても処理をスキップしません.
L.filter
L.filter = curry(function* (f, iter) {
for (const v of iter) {
if (f(v)) yield v;
}
});
go(
[1, 2, 3, 4, 5, 6],
L.map((v) => Promise.resolve(v * v)),
L.filter((v) => v % 2),
take(2),
log,
); // []
現在、L.filter関数ではPromiseに渡される値は受け入れられません.L.filter = curry(function* (f, iter) {
for (const v of iter) {
const value = go1(v, f);
if (value instanceof Promise)
yield value.then((a) => (a ? v : Promise.reject()));
else if (value) yield v;
}
});
go(
[1, 2, 3, 4, 5, 6],
L.map((v) => Promise.resolve(v * v)),
L.filter((v) => v % 2),
take(2),
log,
); // Uncaught (in promise) Symbol(nop)
L.filter関数では、iterableがPromiseでない場合に即座に屈服し、PromiseではPromiseをtake関数に渡してtake関数で値を使用することを実現している.また,PromiseはPromiseであるが,条件を満たさない値は後で伝達されない.拒否(nop)を使用しました.
Symbolを使用する理由は、Symbolの特性が他のプログラムと競合しないため、処理する必要のない値であるためです。
これでtake関数からfilter処理の拒否値を受信すれば終了する.
const take = curry((limit, iter) => {
const res = [];
iter = iter[Symbol.iterator]();
let cur;
return (function recur() {
while (!(cur = iter.next()).done) {
const value = cur.value;
if (value instanceof Promise)
return value
.then((v) => ((res.push(v), res).length === limit ? res : recur()))
.catch((e) => (e === nop ? recur() : Promise.reject(e)));
res.push(value);
if (res.length === limit) return res;
}
return res;
})();
});
go(
[1, 2, 3, 4, 5, 6],
L.map((v) => Promise.resolve(v * v)),
L.filter((v) => v % 2),
take(2),
log,
); // [1, 9]
これでL.filterはPromiseを受信できます.PromiseはKleisli Componentの観点から、拒否された値は後のthenを無視してcatchに移動するため、L.filterの後に他の関数があっても処理をスキップしません.
reduceサポートnop
const reduce = curry((f, acc, iter) => {
if (!iter) {
iter = acc[Symbol.iterator]();
acc = iter.next().value;
} else {
iter = iter[Symbol.iterator]();
}
return go1(acc, function recur(acc) {
let cur;
while (!(cur = iter.next()).done) {
const value = cur.value;
acc = f(acc, value);
if (acc instanceof Promise) return acc.then(recur);
}
return acc;
});
});
現在のreduce関数はPromiseです.拒否()に変換された値を処理できないため、変更しようとします.// 추가된 부분
const reduceInner = (acc, value, f) =>
value instanceof Promise
? value.then(
(v) => f(acc, v),
(e) => (e === nop ? acc : Promise.reject(e)),
)
: f(acc, value);
const reduce = curry((f, acc, iter) => {
if (!iter) {
iter = acc[Symbol.iterator]();
acc = iter.next().value;
} else {
iter = iter[Symbol.iterator]();
}
return go1(acc, function recur(acc) {
let cur;
while (!(cur = iter.next()).done) {
acc = reduceInner(acc, cur.value, f);
if (acc instanceof Promise) return acc.then(recur);
}
return acc;
});
});
反復器の値はPromiseです.拒否()が発生しないように、ReduceInner関数でエラーを処理できます.Reference
この問題について(02.07 TIL), 我々は、より多くの情報をここで見つけました https://velog.io/@dudtjr913/02.07-TILテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol