何时以及如何使用延续传递方式

时间:2009-08-20 22:55:16

标签: c#

我一直在阅读有关继续传递样式编程技术(C#3.0实现)的内容。

为何/何时使用此技术会有用?

如何实现这一点以获得真正的长链?这与currying相同(这会在google中产生更好的搜索结果)吗?

由于

3 个答案:

答案 0 :(得分:12)

Wes Dyer在C#环境中对CPS进行了excellent write-up。我认为我不可能添加任何有意义的东西。如果某些具体事情不明确,请继续询问。

答案 1 :(得分:5)

要回答你的上一个问题,继续传递风格不是一个currying。当你从另一个函数创建一个函数时,你可以通过指定一个或多个参数来进行curry,从而获得一个参数更少的函数。在函数式编程语言(例如F#和C#)中进行一定程度的使用,可以将所有函数视为一个变量的函数。如果所述函数具有多个参数,则可以将其视为具有on参数并返回具有其余参数的另一函数。这是c#中的currying示例:

public static class FuncExtensions
{
        public static Func<A, Func<R>> Curry<A, R>(this Func<A, R> f)
        {
            return a => () => f(a);
        }
}

Func<int, int> f = x => x + 1;

Func<int> curried = f.Curry()(1);

咖喱功能将永远返回2.当然,这有更多的启发性用途。

关于继续传递样式,除了链接到的Wes Dyer博客之外,还要查看F#异步工作流,它们是continuation的实例,或者是continuation monad。您可以尝试使用术语continuation monad来查找其他一些文章。

答案 2 :(得分:0)

我在Riccardo Terrell撰写的“ .NET中的并发,并发和并行编程的现代模式”一书中找到了关于CPS的简短且很好的解释(代码在C#中):

  

有时候,优化的尾调用递归函数不正确   解决方案或可能难以实施。在这种情况下,一种可能   另一种方法是CPS,一种传递结果的技术   功能延续。 CPS用于优化递归   功能,因为它避免了堆栈分配。此外,CPS用于   Microsoft TPL,在C#中异步/等待中,在F#中异步工作流中。   CPS在并发编程中扮演重要角色。以下   代码示例演示如何在函数中使用CPS模式   GetMaxCPS:

static void GetMaxCPS(int x, int y, Action<int> action) => action(x > y ? x : y);

GetMaxCPS (5, 7, n => Console.WriteLine(n));
  

连续传递的参数定义为委托   动作,可以方便地用于传递lambda   表达。有趣的部分是该设计的功能   从不直接返回结果;相反,它将结果提供给   继续过程。 CPS也可以用于实施   使用尾部调用的递归函数。

这里也是Wikipedia的简单简短说明。解释还提到了CPS的好处:

https://en.wikipedia.org/wiki/Continuation-passing_style

  

以连续传递样式编写的函数需要额外花费   参数:明确的“继续”,即一个参数的函数。   当CPS函数计算出其结果值时,它将“返回”它   通过使用该值作为参数调用延续函数。   这意味着在调用CPS函数时,调用函数为   需要提供要与子例程的程序一起调用的过程   “返回”值。以这种形式表达代码可以做很多事情   显式的,以直接样式隐式表示。这些包括:过程   回报,作为继续的呼唤变得显而易见;   中间值,都是给定的名称;论证顺序   明确的评估;和尾叫,简单地叫   具有相同连续性且未修改的过程,该过程已传递给   呼叫者,召集者。

     

当   呼叫者不想等到被呼叫者完成。例如,   在用户界面(UI)编程中,例程可以设置对话框   字段,并将其以及延续功能传递给用户界面   框架。该调用立即返回,允许应用程序代码   在用户与对话框交互时继续操作。一旦   用户按下“确定”按钮,框架调用继续   功能与更新的字段。