Exploring recursive APS and CPS in c #
The 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 called as a common function. 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. Call var ac = Accumulate (1, 20); Use a Lambda expression to implement a tail recursive factorial: static int AccumulateByLambda (int x) {Func <int, int, int> accumulate = null; accumulate = (acc, n) => n = 0? Acc: Accumulate (acc * n, n-1); return accumulate (1, x);} the CPS function is the full name of 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 generally 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) operation steps are 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 <int> 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. After the CPS transformation knows the CPS function, let's take a closer look at the CPS transformation. Console. writeLine (Times3 (5); // CPS transform Times3CPS (5, (reslut) => Console. writeLine (result); The above times3 function is called CPS conversion from direct calling to using "subsequent transfer operation. For example, 1: the conversion of the MAX function static int Max (int n, int m) {if (n> m) return n; else return m;} Console. writeLine (Max (3, 4); to convert this max function to the CPS mode, perform the following steps: 1: Change the return value to void2: 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 <int> 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, G, Main calls F, F calls G. Console. writeLine (F (1) + 1); static int F (int n) {return G (n + 1) + 1;} static int G (int n) {return n + 1;} 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 <int> k) {G (n + 1, x => k (x + 1 ));} static void G (int n, Action <int> 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 C PS tail recursion: Factorial (5, x => Console. writeLine (x); static void Factorial (int n, Action <int> continuation) {if (n = 0) continuation (1); else Factorial (n-1, x => continuation (n * x);} Lao Zhao-tail recursion and Continuation "Calculate the factorial of n, pass the result to 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 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.