Open Eszartek opened 7 years ago
Merged into my master. Considering changing recurse to just be a branch back.
: recurse compile branch last @ code> @ , ; immediate
Wouldn't compiling a branch there effectively be the same a compiling a NOP there? In the end, the code address of the current word being defined just needs to be executed , which comma accomplishes without the help/overhead of a branch call.
Do you see something else of value that the branch adds, perhaps readability? To me, the explicit branch does actually give a cue as to whats going on in that definition of recurse.
The big reason for the branch is to optimize away the call return. Without the branch it will place the current position on the return stack before branching to the code and then when it exits would have to unwind every call it made. The branch simply jumps to the address and will exit from the original function on exit.
Ahh, great explanation. I was going to try to test to see how the return stack was being used in each scenario, as I still don't have a full mental map as to "whats happening when".
So basically, with the branch, you could recurse almost indefinitely without overflowing the return stack?
Edit: testing with :
: fac rpp @ . dup 1 = if drop 1 else dup 1- recurse * then ;
"5 fac ." results with 184 182 180 178 176 120 so I see the return stack being consumed.
Now to figure out why the branch version isn't working. Perhaps it's short circuiting the "then" at the end of the factorial word. "5 fac ." results with 184 184 184 184 184 1 so it is recursing, just not hitting the multiplication.
I see the problem now, the original RECURSE does work as designed.
OK. : fact RECURSE DUP 1 > IF DUP 1- fact * THEN ;
OK. 5 fact
OK. .S
120 <SP
All RECURSE does is allow you to refer to the definition before the end of the definition, nomally function isn't usable until after ; this is so can use an earlier definition of a word within a new definition.
: fact DUP FOR AFT R@ DUP IF * THEN THEN NEXT ;
This is the non recursive way. It runs the loop x number of times duping the initial count. The AFT THEN will make the loop skip first iteration. R@ will count down to 0.
For the original design, it should be named "recursive" so that the behavior is understood. Then the recurse word could be included as well (just not ever needed together in the same definition). It appears that gforth has both words, so depending on your style you could use either:
https://www.complang.tuwien.ac.at/forth/gforth/Docs-html/Recursion-Tutorial.html
I haven't looked at gforth before, so I was unaware of the word "recursive". I like it!
http://www.forth.org/eforth.html
This is the forth I was referencing. Originally my goal was to see what the minimal implementation would require to implement since it is based on a handful of primitives.
It's all clear now, It just took a few gyrations for it to come together for me.
Excellent.
Using the following factorial definition as a test:
"5 fac ." returns 20 as a result which is incorrect.
Redefining recurse (and fac again which depends on it) as :
"5 fac ." returns 120 as a result, which is correct.