Exploring recursive APS and CPS in c #
Accumulator passing style)
Tail recursion is optimized so that the stack does not need to save the last returned address/status value, so that the recursive function is treated as a common function call.
Recursion is actually dependent on the previous value to calculate the next value. If we can save the last value and pass it in the next call without directly referencing the value returned by the function. So that the stack is released, and tail recursion optimization is achieved.
Next, we add the acc parameter, which stores the last value and is passed in during the next call.
Static int Accumulate (int acc, int n)
{
If (n = 0)
Return acc;
Return accumulate (acc * n, n-1 );
}
When using Accumulate recursion, we only need to use the last return value. The call is as follows:
Var ac = Accumulate (1, 20 );
Use Lambda expressions to implement tail recursion factorial:
Static int AccumulateByLambda (int x)
{
Func accumulate = null;
Accumulate = (acc, n) => n = 0? Acc: Accumulate (acc * n, n-1 );
Return accumulate (1, x );
}
CPS Functions
CPS stands for the Continuation passing style.
Static int Times3 (int x)
{
Return x * 3;
}
Console. WriteLine (Times3 (5 ));
The above function times the input value by 3, which is usually written in this way. In fact, we can also use the C # syntax of the returned function to construct the nested method and change the function call to the call chain times3 (3) (5 ).
This method is intuitive and normal in mathematics or functional programming, but it is not so intuitive in the script language c.
The Continuation term in CPS refers to the remainder of the computation, similar to the times3 (3) (5) red part.
For example, the expression a * (B + c) has multiple calculation steps. C # can be written as the following function:
Console. WriteLine (Mult (a, Add (B, c )))
The procedure is as follows:
B and c are added.
Multiply the result by.
Output result.
When one step is performed, the subsequent operations are 2 or 3. When two steps are performed, the subsequent operation is 3. Use the CPS mode to transform the times3 function:
Static void Times3CPS (int x, Action continuation)
{
Continuation (x * 3 );
}
Times3CPS (5, (reslut) => Console. WriteLine (result ));
We added a function parameter indicating the next operation 3, and passed the subsequent operation during the call. This is the CPS function.
CPS Transformation
After learning about the CPS function, let's take a closer look at the CPS transformation.
Console. WriteLine (Times3 (5 ));
// CPS Transformation
Times3CPS (5, (reslut) => Console. WriteLine (result ));
The above times3 function is called CPS conversion from direct calls to the use of "subsequent transfer operations.
Example 1: MAX Function Conversion
Static int Max (int n, int m)
{
If (n> m)
Return n;
Else
Return m;
}
Console. WriteLine (Max (3, 4 ));
To convert the max function to the CPS mode, perform the following steps:
1: Change the return value to void.
2: add an additional type parameter Action. T is the original return type.
3: replace all original return declarations with the parameters of subsequent operation expressions.
Static void Max (int n, int m, Action k)
{
If (n> m)
K (n );
Else
K (m );
}
Max (3, 4, x => Console. WriteLine (x ));
Example 2: if there are three functions Main, F, and G, Main calls F and F call G.
Console. WriteLine (F (1) + 1 );
Static int F (int n)
{
Return G (n + 1) + 1;
}
Static int G (int n)
{
Return n + 1;
}
We Convert F and G to the CPS style. The conversion steps are the same as those of Max functions:
F (1, x => Console. WriteLine (x + 1 ));
Static void F (int n, Action k)
{
G (n + 1, x => k (x + 1 ));
}
Static void G (int n, Action k)
{
K (n + 1 );
}
CPS tail recursion
This is a traditional recursive factorial:
Static int Factorial (int n)
{
If (n = 0)
Return 1;
Else
Return n * Factorial (n-1 );
}
Use the same procedure to convert recursion to CPS tail recursion:
Factorial (5, x => Console. WriteLine (x ));
Static void Factorial (int n, Action continuation)
{
If (n = 0)
Continuation (1 );
Else
Factorial (n-1, x => continuation (n * x ));
}
Lazhao-tail recursion and Continuation
"Calculate the factorial of n, pass the result into the continuation method, and return", that is, "Calculate the factorial of n-1, multiply the result with n, and then call the continuation method ". To implement the logic of "multiply the result with n and then call the continuation method", the Code constructs an anonymous method and passes in the Factorial method again.
Summary
The CPS mode is very powerful and can be used in many aspects. For example, in the implementation of the compiler, the CPS-style parser combination sub-, and callback after the function is completed. It can also be said that the original internal control operations of the program are extracted by using the CPS method and exposed to the programmer, for example, the example in this article.
Note: For more exciting tutorials, please follow the help houseWebpage Design tutorialTopic,