Javascript 蹦床、递归和惰性评估

Javascript 蹦床、递归和惰性评估,javascript,recursion,functional-programming,lazy-evaluation,trampolines,Javascript,Recursion,Functional Programming,Lazy Evaluation,Trampolines,我试图用JavaScript实现基本的惰性序列。我只使用闭包和连续体。到目前为止,我得到的是: var cons = curry(function(x, y, list){ return list(x, y); }); var head = function(seq){ return seq(function(x, y){ return x; }); }; var tail = function(seq){ return seq(function(x, y){ r

我试图用JavaScript实现基本的惰性序列。我只使用闭包和连续体。到目前为止,我得到的是:

var cons = curry(function(x, y, list){
  return list(x, y);
});
var head = function(seq){
  return seq(function(x, y){
    return x;
  });
};
var tail = function(seq){
  return seq(function(x, y){
    return y();
  });
};
var iterate = function(f){
  var next = f();
  if (next != null) {
    return cons(next, function(){
      return iterate(f);
    });
  }
};
var take = curry(function(n, seq){
  if (n && seq != null) {
    return cons(head(seq), function(){
      return take(n - 1, tail(seq));
    });
  }
});
var doSeq = curry(function(n, f, seq){
  while (n-- && seq != null) {
    f(head(seq));
    seq = tail(seq);
  }
});

var rand = iterate(Math.random);
var log = function(x){ console.log(x) };

doSeq(10, log, rand); //=> logs 10 random numbers
我没有发布函数,因为它与问题没有直接关系

现在交易破坏者是
过滤器
。规范实现是尾部递归的:

var filter = curry(function(f, seq){
  if (seq == null) {
    return;
  }
  if (!f(head(seq))) {
    return filter(f, tail(seq)); // recursion
  }
  return cons(head(seq), function(){
    return filter(f, tail(seq));
  });
});
当我在一个序列上多次运行它时,堆栈最终会爆炸:

我知道一个常见的解决方法是使用,在一个渴望的世界中,这相对容易,但对于一个懒惰的序列来说,实现它似乎让人望而生畏。我发现了一个复杂的问题,但我放弃了用JavaScript实现它

这有看起来那么复杂吗?有没有其他方法来解决这个问题,也许是迭代?关于以合理的方式将Scheme代码移植到JavaScript有什么提示吗

我认为这应该在仍然懒散的时候做到1:

也许更容易阅读:

var filter = curry(function(f, seq){
  for (; seq != null; seq = tail(seq))
    if ( f(head(seq)) )
      return cons(head(seq), function() {
        return filter(f, tail(seq))
      });
});

1) :您对惰性序列的表示似乎无法表示一个可能为空(尚未确定)的列表

如果该列表仍然与递归版本一样惰性,那么方案解决方案是否有必要?顺便说一句,我已经尝试了
常量
,但它有一个问题,它会根据组合顺序炸毁堆栈,请看,哎哟,当然
常量
函数不是惰性计算的-我在Haskell中太多了:-/好的,所以我想我要用这个。我太过关注递归函数的蹦床,以至于错过了显而易见的。。。谢谢。实际上我认为循环中的
seq=tail(seq)
是蹦床:-)是的,一般来说我认为是这样,但方案解决方案似乎建议了一种方法来蹦床一个承诺,如果我理解正确的话,这个承诺将在以后执行thunk,甚至更懒。顺便说一句,你的
iterate
函数不是很实用,因为它不保存任何状态。使用
function iterate(f,cur){if(cur!=null){var next=f(cur);return cons(cur,function(){return iterate(f,next);}}}
这样
var ints=iterate(function(x){return x+1},0)
是的,我只是使用IIFE闭包来跟踪当前的值,正如您在JSBin演示中看到的那样。是的,但这不起作用<代码>头部(尾部(内部))!=头部(尾部(内部)-等等,什么?!每次
tail
调用都会使结果增加一个。我没有跟踪。。。它很好用,我不知道你的意思,我试过ints,fibos。。。Try-当第一次发出
int
警报时,我希望总是得到
1
var filter = curry(function(f, seq){
  for (; seq != null; seq = tail(seq))
    if ( f(head(seq)) )
      return cons(head(seq), function() {
        return filter(f, tail(seq))
      });
});