Why stack stack is required in the program?
In ordinary programs, the concept of access to subroutines and functions, it is very intuitive to call the subroutine, will first stop the current thing, instead of executing the called subroutine, and so on after the completion of the subroutine, and then pick up the previously suspended program, it is possible to use the data that the subroutine has just calculated. But it takes a mechanism to re-pick up the program where the program is suspended and to continue executing, that is, to store information about what is currently being done and where to pick up the program (site information). At this point, the stack is naturally a data structure that satisfies this need (why not use the stack to mention it).
What if the situation changes and no function needs to be returned, the function terminates the program, or calls another function?
Obviously, treatment is worse than a disease. In this case, you don't have to keep track of what you're doing, because it never returns, and every time you call a process that takes all the control and no longer returns, how do I get all the work done?
First, write a function, and then at the end of the function call another function ( tail call ). Control is no longer returned, so there is no point in any code after calling the function.
Second, suppose you have more to do after calling the function foo. Foo is now in the same position as you, according to the above, the last thing that calls the function either terminates the program or calls other functions, so you need to put the extra work into a function bar and expect it to execute after Foo, that is, make sure Foo calls bar instead of terminating the program.
But you didn't write Foo, how do you know Foo will call bar when it's finished? You need to tell Foo to get foo to call bar, and you want Foo to work together. (Nonsense ...) )
Thirdly, if someone calls your function, the last thing you need to do is the same, because your function will not return. You need to look for some way to allow the caller of the function to tell you what to do after you have finished your work.
The idea of this function is never to return, the caller passes in their function information (this function information indicates what to do next), which is a bit strange, but it is a very powerful programming style, this is the legendary continuation passing style. Continuation refers to the "what to do next" message, which is passed from one function to another, hence the name.
Many languages naturally support cps--scheme, Ruby and Rhino. CPS makes it unnecessary to use stacks (to store field information) in our normal recursive programs.
The following will write out the two styles of mixed CPS and general program code, in JScript language.
Suppose you have the following JScript program code snippet
function foo (x) { var y = bar (); Blah (x, y);} function Bar () { return ten;} function blah (A, b) { + b);} Foo (1);
This piece of code is intuitive. So how to write CPS style? First, each function needs to add an extra parameter to keep the continuation. Our program calls Foo and terminates, so calling Foo's continuation is "terminating the program." Assuming that there is now a magic function to terminate the program,
function foo (x, Cfoo) { // undone:rewrite foo in CPS}foo (1, terminate);
To get a second look, call Foo to make sure the following three things are done in order:
1. Run Bar
2. Running blah
3. The continuation provided by the caller who runs Foo
But Blah won't return, so we need to get blah to call Foo's continuation after completing its own task, so rewrite blah as follows
function (x, Cfoo) { var y = bar (); Blah (x, y, Cfoo);}
It now seems to be possible to ensure that Foo's continuation can be called to terminate the program, but Bar is also designed to not return, so it is not possible to call blah in this way.
Another problem is that bar will return a value that is used in subsequent tasks, but we have removed the return value of the function. The workaround is to have bar have a continuation parameter and then use the return value of bar (which refers to the return value of the original bar) as the continuation parameter. Before you return the return value to the place where you are about to continue to run the program, you will now pass the return value to the next thing you are going to do, the truth is the same.
But what will foo continuation to bar? Well, when Bar calls Foo to its continuation (this continuation will apply a parameter that is the return value of the previous bar), what does Foo want to do?
This is simple, Foo wants to use the return value of bar and its own parameters to call blah, so the overriding function is as follows:
function foo (x, Afterfoo) { function Foocontinuation (y) {blah (x, y, Afterfoo); }} function bar (Afterbar) {Afterbar ( 10);} function blah (A, B, Afterblah) {print (a +b, Afterblah);} function print (A, afterprint) // overload print {print (a); Afterprint ();} Foo ( 1, terminate);
Foocontinuation is a closure (closure), so it encapsulates the value of x and Afterfoo information, which is then passed to bar.
The summary process is as follows:
- The program passed to Foo with a parameter of 1 and terminate
- Foo passed the bar parameter to Foocontinuation
- Bar passed to foocontinuation with a parameter of 10
- Foocontinuation gives blah parameters of 1, 10 and terminate
- Blah adds the parameters to 11 and then passes 11 and terminate to print
- Print 11, then call terminate, end the program
In practice, JScript does not know that these functions do not return a value. JScript is also not smart enough to realize that even if these functions return values, these functions will not do anything after the subroutine call is complete, so it is not necessary to keep the information of the old frames in the stack.
Original: https://blogs.msdn.microsoft.com/ericlippert/2005/08/08/recursion-part-four-continuation-passing-style/
Recursive--cps (i)