首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Javascript ES6:实现展开函数的生成器

Javascript ES6:实现展开函数的生成器
EN

Stack Overflow用户
提问于 2020-04-25 08:19:11
回答 1查看 122关注 0票数 0

我正在尝试重构这段代码,它定义了一个unfold函数,并使用它来创建count函数,该函数在数组中填充直到计数为止的数字。我不想调用count(100),而是想把count变成一个生成器,它可以通过任意调用next()来使用。

代码语言:javascript
复制
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调用之后结束:

代码语言:javascript
复制
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;
}
EN

回答 1

Stack Overflow用户

发布于 2020-04-25 15:51:47

我想向您展示一个尽可能接近FP中原始展开实现的实现。希望从那里你可以用命令式生成器来实现它。

这是unfoldr的第一个版本

代码语言:javascript
复制
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

代码语言:javascript
复制
unfoldr = f => state => {
  const go = ([x, state_]) =>
    state_ === undefined
      ? []
      : arrCons(x) (thunk(() => go(f(state_))));

  return go(f(state));
};

现在我们模拟了非严格计算,递归步骤中的表达式的计算刚刚好,即简化为[x, Thunk]形式

这就是它所需要的。请注意,我们使用[]来指示基本情况,从而结束展开过程。我们应该用标记的联合来编码这个行为,即Option/Maybe类型。但为了简单起见,我让实现保持原样。

下面是一个通过定义斐波那契数列来使用unfoldr的例子:

代码语言:javascript
复制
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的完整实现

代码语言:javascript
复制
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]);

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61419411

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档