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

Javascript ES6:实现展开函数生成器,javascript,ecmascript-6,functional-programming,generator,Javascript,Ecmascript 6,Functional Programming,Generator,我正在尝试重构这段代码,它定义了一个展开函数,并使用它来生成计数函数,该函数用数字填充数组,直到计数为止。我不想调用count(100)而是想把count变成一个生成器,可以通过调用next()任意使用它 function unfold (fn, state) { return fn( (value, nextState) => { return [ value, ...unfold (fn, nextState)] },

我正在尝试重构这段代码,它定义了一个
展开
函数,并使用它来生成
计数
函数,该函数用数字填充数组,直到计数为止。我不想调用
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
    );
}
这里的流程已经有点难以理解,我很难弄清楚收益率报表的流程应该如何工作。我想生成结果数组,即
unfold
函数
return[value,…unfold(fn,nextState)]
的第4行,但不确定如何将该结果一直传递到count函数

这就是我到目前为止得到的结果,但它只返回一个包含一个生成器的生成器,然后在几个
下一个
调用后结束:

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 = f => state => {
  const go = ([x, state_]) =>
    state_ === undefined
      ? []
      : arrCons(x) (go(f(state_)));
//                  ^^^^^^^^^^^^^ strictly evaluated

  return go(f(state));
};
unfoldr = f => state => {
  const go = ([x, state_]) =>
    state_ === undefined
      ? []
      : arrCons(x) (thunk(() => go(f(state_))));

  return go(f(state));
};
展开是一个内在无限的过程,因此你需要懒散来阻止它。更准确地说,你需要一个函数来构建这个结构,它的第二个参数是非严格的
arrCons
在这两个参数中都可能是非严格的,因为它所做的只是将它们存储在一个类似成对的数据类型中。然而,Javascript是经过严格评估的

让我们假设我们有一个函数
thunk
,它向Javascript引入了一个隐式thunk,也就是说,一个空函数,您可以在没有括号的情况下调用它,就像对象上的惰性getter一样。它只接受一个普通的空函数,并将其转换为隐式函数。这是我们更新的
展开器

unfoldr = f => state => {
  const go = ([x, state_]) =>
    state_ === undefined
      ? []
      : arrCons(x) (go(f(state_)));
//                  ^^^^^^^^^^^^^ strictly evaluated

  return go(f(state));
};
unfoldr = f => state => {
  const go = ([x, state_]) =>
    state_ === undefined
      ? []
      : arrCons(x) (thunk(() => go(f(state_))));

  return go(f(state));
};
现在我们模拟了非严格求值,递归步骤中的表达式的求值刚好足够,即简化为
[x,Thunk]

这就是一切。请注意,我们使用
[]
表示基本情况,从而表示展开过程的结束。我们更应该用标记的联合来编码这种行为,即
选项
/
可能
类型。但是为了简单起见,我将实现保持原样

下面是通过定义斐波那契序列来使用
unfover
的示例:

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
下面是使用
thunk
返回
代理的完整实现:

const thunk=f=>
新代理(f,新ThunkProxy(f));
const THUNK=“scriptum_THUNK”;
类ThunkProxy{
建造师(f){
this.memo=未定义;
}
应用(g,that,args){
如果(this.memo==未定义)
this.memo=g();
返回此.memo(…args);
}
定义属性(g,k,描述符){debugger;
如果(this.memo==未定义)
this.memo=g();
Object.defineProperty(this.memo,k,descriptor);
返回true;
}
得到(g,k){
如果(this.memo==未定义)
this.memo=g();
如果(k==THUNK)
返回true;
else if(k==Symbol.toPrimitive)
return()=>this.memo;
否则如果(k==“valueOf”)
return()=>this.memo;
否则返回此。备忘录[k];
}
has(g,k){
如果(this.memo==未定义)
this.memo=g();
在这个备忘录中返回k;
}
集合(g、k、v){
如果(this.memo==未定义)
this.memo=g();
此.memo[k]=v;
返回true;
}  
}
常数arrCons=头=>尾=>
[头,尾];
常量arrunbover=f=>state=>{
常数go=([x,状态])=>
状态==未定义
? []
:arrCons(x)(thunk(()=>go(f(state)));
返回go(f(state));
};
常数fibs=arrunfor(
([x,y])=>[x[y,x+y]])([0,1]);
const main=fibs[1][1][1][1][1][1][1][1];//[55,Thunk]
console.log(main[0])