我List在Javascript中实现了一个Scott编码类型以及一个append模仿Semigroup类型类的重载函数.
append工作得很好,但对于大型列表,它会炸掉堆栈.这是我实施的决定性部分:
appendAdd("List/List", tx => ty => tx.runList({
Nil: ty,
Cons: x => tx_ => Cons(x) (append(tx_) (ty))
}));
Run Code Online (Sandbox Code Playgroud)
通常我使用蹦床来避免不断增长的堆栈,但这预示着尾递归,因此在这种情况下不起作用.
由于这个实现是基于Haskell的,我想懒惰的评估和保护的递归/尾递归模数缺点有所不同:
(++) [] ys = ys
(++) (x:xs) ys = x : xs ++ ys
Run Code Online (Sandbox Code Playgroud)
如果我理解正确的话,由于懒惰的评估(差不多),当我向另一个人添加一个列表时,Haskell中没有任何事情发生,直到我真正对这个新列表做了一些事情.在下面的例子中,我折叠它.
我不明白的是,保护递归如何保持递归不会增加调用堆栈以及是否可以在严格评估的语言(如Javascript)中显式实现此行为.
希望这个问题不是太宽泛.
为了更好地理解,这里是完整的实现/示例:
// type constructor
const Type = name => {
const Type = tag => Dcons => {
const t = new Tcons();
Object.defineProperty(
t,
`run${name}`,
{value: Dcons});
t[TAG] = tag;
return t;
};
const …Run Code Online (Sandbox Code Playgroud)