簡體   English   中英

fix 可以尾遞歸,從而表示為一個簡單的循環嗎?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM