蹦床,递归和懒惰的评价

时间:2014-03-05 16:33:03

标签: 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){
    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

我没有发布curry函数,因为它与问题没有直接关系。

现在交易破坏者是filter。规范实现是尾递归的:

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

当我在序列上多次运行时,堆栈最终会爆炸:

Imgur

我知道一个常见的解决方法是使用trampoline,这在一个热切的世界中相对容易,但是对于一个懒惰的序列实现它似乎令人生畏。我发现了一个错综复杂的solution in Scheme,但我放弃了尝试在JavaScript中实现它。

这看起来很复杂吗?有没有其他方法可以解决这个问题,迭代可能吗?有关以一种理智的方式将Scheme代码移植到JavaScript的任何提示?

1 个答案:

答案 0 :(得分:2)

我认为这应该是而懒惰 1

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

可能更容易阅读:

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):你对懒惰序列的表示似乎没有办法表达一个可能为空(但尚未确定)的列表