我正在尝试重构这段代码,它定义了一个unfold函数,并使用它来创建count函数,该函数在数组中填充直到计数为止的数字。我不想调用count(100),而是想把count变成一个生成器,它可以通过任意调用next()来使用。
function unfold (fn, state) {
return fn(
(value, nextState) => {
return [ value, ...unfold (fn, nextState)]
},
()=>[],
state
);
}
function count (max) {
return unfold(
(next, done, state)=>{
return state >= max ?
done() :
next(state, state +1)
},
0
);
}这里的流程已经有点难以理解了,我很难弄清楚yield语句的流程应该如何工作。我想要生成结果数组,它是计数函数return [ value, ...unfold (fn, nextState)]的第4行,但不确定如何将该结果数组一直传递到unfold函数。
这就是我到目前为止所知道的,但它只是返回一个生成器,其中包含一个生成器,然后在几个next调用之后结束:
function * _unfold (fn, base) {
yield * fn(
(value, nextState)=>([ value, ..._unfold (fn, nextState)]),
base
)
return [];
}
function * count (max) {
yield * _unfold(
compress,
0
);
return 0;
}
function * compress (next, state) {
yield next(state, state +1)
return null;
}发布于 2020-04-25 15:51:47
我想向您展示一个尽可能接近FP中原始展开实现的实现。希望从那里你可以用命令式生成器来实现它。
这是unfoldr的第一个版本
unfoldr = f => state => {
const go = ([x, state_]) =>
state_ === undefined
? []
: arrCons(x) (go(f(state_)));
// ^^^^^^^^^^^^^ strictly evaluated
return go(f(state));
};展开是一个本质上无限的过程,因此你需要懒惰来阻止它。更准确地说,您需要一个构建结构的函数,该函数在第二个参数中是非严格的。arrCons在这两个参数中都可以是非严格的,因为它所做的就是将它们存储在一个类似对的数据类型中。但是,Javascript是严格计算的。
让我们假设我们有一个函数thunk,它向Javascript引入了一个隐式的thunk,也就是说,一个空函数,你可以像对象上的惰性getter一样调用它而不用括号。它只需要一个普通的空值函数,并将其转换为隐式函数。这是我们更新后的unfoldr
unfoldr = f => state => {
const go = ([x, state_]) =>
state_ === undefined
? []
: arrCons(x) (thunk(() => go(f(state_))));
return go(f(state));
};现在我们模拟了非严格计算,递归步骤中的表达式的计算刚刚好,即简化为[x, Thunk]形式
这就是它所需要的。请注意,我们使用[]来指示基本情况,从而结束展开过程。我们应该用标记的联合来编码这个行为,即Option/Maybe类型。但为了简单起见,我让实现保持原样。
下面是一个通过定义斐波那契数列来使用unfoldr的例子:
const arrCons = head => tail =>
[head, tail];
const unfoldr = f => state => {
const go = ([x, state_]) =>
state_ === undefined
? []
: arrCons(x) (thunk(() => go(f(state_))));
return go(f(state));
};
const fibs = unfoldr(
([x, y]) => [x, [y, x + y]]) ([0, 1]);
const main = fibs[1] [1] [1] [1] [1] [1] [1] [1] [1] [1]; // [55, Thunk]
main[0]; // 55下面是返回Proxy的thunk的完整实现
const thunk = f =>
new Proxy(f, new ThunkProxy(f));
const THUNK = "scriptum_thunk";
class ThunkProxy {
constructor(f) {
this.memo = undefined;
}
apply(g, that, args) {
if (this.memo === undefined)
this.memo = g();
return this.memo(...args);
}
defineProperty(g, k, descriptor) { debugger;
if (this.memo === undefined)
this.memo = g();
Object.defineProperty(this.memo, k, descriptor);
return true;
}
get(g, k) {
if (this.memo === undefined)
this.memo = g();
if (k === THUNK)
return true;
else if (k === Symbol.toPrimitive)
return () => this.memo;
else if (k === "valueOf")
return () => this.memo;
else return this.memo[k];
}
has(g, k) {
if (this.memo === undefined)
this.memo = g();
return k in this.memo;
}
set(g, k, v) {
if (this.memo === undefined)
this.memo = g();
this.memo[k] = v;
return true;
}
}
const arrCons = head => tail =>
[head, tail];
const arrUnfoldr = f => state => {
const go = ([x, state_]) =>
state_ === undefined
? []
: arrCons(x) (thunk(() => go(f(state_))));
return go(f(state));
};
const fibs = arrUnfoldr(
([x, y]) => [x, [y, x + y]]) ([0, 1]);
const main = fibs[1] [1] [1] [1] [1] [1] [1] [1] [1] [1]; // [55, Thunk]
console.log(main[0]);
https://stackoverflow.com/questions/61419411
复制相似问题