![](/img/trans.png)
[英]Simple tail-call optimization for recursive, while-loop style functions
[英]Can fix be tail recursive and thus expressed as a simple loop?
我不知道如何將fix
表示為尾遞歸算法。 或者它已經是尾遞歸了? 可能是我多慮了...
const fix = f => x => f(fix(f)) (x); // redundant eta abstraction due to eager eval const sum = fix(go => acc => ([x, ...xs]) => x === undefined ? acc : go(acc + x) (xs)) (0); const main = sum([1,2,3,4,5]); console.log(main); // 15
我嘗試了很多,但還沒有想出任何遠程有用的東西。 尾遞歸算法可以輕松轉換為堆棧安全循環。 這才是真正的目標。
我不知道如何將
fix
表示為尾遞歸算法。
首先,將fix
的定義轉換為A 范式。
// fix :: ((a -> b) -> a -> b) -> a -> b
const fix = f => x => {
const g = fix(f);
const h = f(g);
const y = h(x);
return y;
};
接下來,將生成的程序轉換為continuation-passing style 。
// type Cont r a = (a -> r) -> r
// fix :: ((a -> Cont r b) -> Cont r (a -> Cont r b)) -> Cont r (a -> Cont r b)
const fix = f => k => k(x => k =>
fix(f) (g =>
f(g) (h =>
h(x) (y =>
k(y)))));
現在, fix
是尾遞歸的。 但是,這可能不是您想要的。
尾遞歸算法可以輕松轉換為堆棧安全循環。 這才是真正的目標。
如果您只想要堆棧安全,那么您可以使用Trampoline
monad。
// Bounce :: (a -> Trampoline b) -> a -> Trampoline b const Bounce = func => (...args) => ({ bounce: true, func, args }); // Return :: a -> Trampoline a const Return = value => ({ bounce: false, value }); // trampoline :: Trampoline a -> a const trampoline = result => { while (result.bounce) result = result.func(...result.args); return result.value; }; // fix :: ((a -> Trampoline b) -> a -> Trampoline b) -> a -> Trampoline b const fix = f => Bounce(x => f(fix(f))(x)); // id :: a -> a const id = x => x; // reachable code console.log("begin"); // open the console in your browser // infinite loop trampoline(fix(id)(0)); // unreachable code console.log("end");
但是,這也需要您更改sum
的定義。
// Bounce :: (a -> Trampoline b) -> a -> Trampoline b const Bounce = func => (...args) => ({ bounce: true, func, args }); // Return :: a -> Trampoline a const Return = value => ({ bounce: false, value }); // trampoline :: Trampoline a -> a const trampoline = result => { while (result.bounce) result = result.func(...result.args); return result.value; }; // fix :: ((a -> Trampoline b) -> a -> Trampoline b) -> a -> Trampoline b const fix = f => Bounce((...args) => f(fix(f))(...args)); // _sum :: (Number, [Number]) -> Trampoline Number const _sum = fix(recur => (acc, xxs) => { if (xxs.length === 0) return Return(acc); const [x, ...xs] = xxs; return recur(acc + x, xs); }); // sum :: [Number] -> Trampoline Number const sum = xxs => _sum(0, xxs); // result :: Number const result = trampoline(sum([1,2,3,4,5])); // 15 console.log(result);
希望有幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.