C #-continuation-Passing Style (CPS)

Source: Internet
Author: User

If you are not familiar with what CPS is, we recommend several links (hopefully your English will be awesome ):

Http://blogs.msdn.com/ B /wesdyer/archive/2007/12/22/continuation-passing-style.aspx

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

Http://blogs.msdn.com/ B /ericlippert/archive/2010/10/22/continuation-passing-style-revisited-part-two-handwaving-about-control-flow.aspx

 

CPS (continuation-Passing Style): it can be understood as a subsequent transfer format, which is a feature in functional programming. However, the combination of lambda expressions and action <t> generic delegation in C # can achieve this feature well.

 

Previously, we used a structured approach to handle exceptions:

Void Q ()
{
Try
{
B (());
}
Catch
{
C ();
}
D ();
}

Int A (int)
{
Throw;
Return 0; // inaccessible, temporarily ignored

}
Void B (INT X) {// To Do Something}
Void C () {// To Do Something}
Void D () {// To Do Something}

 

Whether these method calls are object-oriented is not a topic to be discussed. However, try {...} catch {...} finally {...}, a structured exception handling method, is still widely used.

 

A structural feature with strong coupling and high correlation. It is closely integrated like an assembly line.

Let's take a look at the call process:

First, execute method A. If method A does not produce any exception, return the result to Method B as a parameter and call Method B. If Method B runs normally. Method C will not be executed, and it will jump directly to method D to start execution.

If either method A or method B has an exception, the execution will be suspended. The call will jump to method C for execution (the premise is that the exception can be captured smoothly ). Finally, call method D.

 

In fact, when CLR adopts a structured exception handling mechanism, it implements some internal and language mechanisms such as handsome selector and processor. For details, refer to CLR via C #3.0. However, since we say that this exception handling method is interlocking and similar to streaming, why can't we simulate the use of CPS?

For the four methods of ABCD, we consider two cases (in fact, it is an if... else .... structure): method call succeeded; method call failed.

Therefore, you can define it as follows:

Action <t>: accept a parameter of type T with no return value;

Void A (Action <int> normal, Action error );

Void B (INT X, Action normal, Action error) {whatever}
Void C (Action normal, Action error) {whatever}
Void D (Action normal, Action error) {whatever}

Note: All normal operations can be imagined as: we usually do not consider the abnormal method bodies. All errors can be considered as the handling methods for exceptions in the original method bodies.

 

The processing logic of the try block is abstracted:

Try (
/* Trybody */(bodynormal, bodyerror) => (
/* Normal for a */x => B (X, bodynormal, bodyerror ),
/* Error for a */bodyerror ),
/* Catchbody */C,
/* Outernormal */() => D (qnormal, qerror ),
/* Outererror */qerror );
First, the try block can only have two egress ports:

Run the following command by try --> outernormal: () => D (qnormal, qerror) with outernormal

Try --> catchbody: () => C (outernormal, outererror): () => C () => D (qnormal, qerror), outererror)

For try objects, there are:(Bodynormal, bodyerror) => A (x => B (X, bodynormal, bodyerror), bodyerror );

Therefore, the expansion is as follows:

 

 

 

A (
X => B (// A's normal continuation
X, // B's argument
() => D (// B's normal continuation
Qnormal, // D's normal continuation
Qerror), // D's error continuation
() => C (// B's error continuation
() => D (// C's normal continuation
Qnormal, // D's normal continuation
Qerror) , // D's error continuation
Qerror), // C's error continuation
() => C (// A's error continuation
() => D (// C's normal continuation
Qnormal, // D's normal continuation
Qerror) , // D's error continuation
Qerror) // C's error continuation

 

If C throws an exception, continuation is immediately transferred to qerror for execution;

In terms of readability, this is certainly not a very good implementation method. However, this is an idea. We can use this method when writing some highly correlated method calls, and there are not many method calls.

 

The following implementation demonstrates the transfer of CPS's stream calling (pseudo recursion) and data processing control:

Implement factorial:

Static voidMain () {factorial (5, x =>Console. Writeline (x ));}Static voidFactorial (IntN,Action<Int> K ){If(N = 0) K (1 );ElseFactorial (n-1, x => K (N * X ));}
Of course, CPS also has a very useful feature that supports asynchronous callback and is useful in asynchronous programming.
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.