gpt4 book ai didi

JavaScript ES6 : Implementing generator for unfold function

转载 作者:行者123 更新时间:2023-12-02 20:58:17 24 4
gpt4 key购买 nike

我正在尝试重构这段代码,它定义了一个 unfold 函数,并使用它来创建 count 函数,该函数用最多可达 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语句的流程应该如何工作。我想生成结果数组,它是 unfold 函数 return [ value, ...unfold (fn, nextState)] 的第 4 行,但我不确定如何传递一直到计数函数。

这就是我到目前为止所拥有的,但它只是返回一个生成器,其中包含一个生成器,然后在几次 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;
}

最佳答案

我想向您展示一个尽可能接近 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

这是返回 Proxythunk 的完整实现:​​

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]);

关于JavaScript ES6 : Implementing generator for unfold function,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61419411/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com