There's a lot of discussion online about recursion, but most of it missed the mark as I've been studying the topic.
So instead of the usual things that get said when trying to teach recursion, I'm going to say a couple things that help me:
- Yes, recursion is calling a method inside of itself; however....
- The parameter/argument that's passed into the 2nd method call must change the input...typically by reducing the original parameter by one, or by half (or some other amount)
- It helps to think of Ruby as "pausing" the 1st call, and then "starting" the second call....and then "pausing" the 2nd call, and starting the 3rd call...etc
- Often times, it's necessary to write a method with a solution parameter set to an empty default array
- Try writing each step down with pen and paper!
- The method will have at least a base case and a process to reduce to the base case. Usually this takes the form of an
if-elseclause - When a method is called inside itself...Ruby will not move on until it has a return value from that method. Then it will "unpause" (see number 3 above) and continue
I'll elaborate on each of these steps, to illustrate.
The basic setup for a recursive method typically looks like this:
def recursive_method(input, solution = [])
if input.length == 1 # this could be something different, but it will often be *similar* to this
# this is the base case
else
# the process to reduce the input to the base case scenario
recursive_method(input.altered_somehow, solution)
end
solution
endIt's not challenging, and it's not always this simple. However, learning about recursion is hard enough...it shouldn't feel like re-inventing the wheel.
A recursive method is typically written to work with some set of data. Typically it's taught that the input will be an Array.
So in the example above, input will be an Array.
Now observe the recursive_method inside the method. Notice the input? it's input.altered_somehow.
If you're building a recursive method and the internal method call doesn't alter the input somehow....you're going to have a very difficult time.
Depending on the type of problem that's attempting to be solved, it may be necessary to decrease the input by 1. Or it maybe necessary to decrease the input by half.
If you need to cut things in half, remember that you can still assign variables within the method, and assign half the value of the original input to it! and assign the second half to a different variable!
If you called a method once inside itself, you can be sure it's ok to call it a second time within itself... mind blown
This should probably be tied in with #5...but it does help to think of Ruby starting and pausing.
So if Ruby starts a method....and then gets to the line inside the method that is a call to another method...Ruby will "pause" the first call and do the second call.
I'm not gonna say more here until I get to step 5.
Take a look back in the original skeleton I wrote in section 1.
def recursive_method(input, solution = [])Now, when this is called, I won't have to explicitly pass in the second parameter!
But take a look at the call to the recursive method inside!
recrusive_method(input.altered_somehow, solution)solution is no longer a default parameter! It's a specifically defined parameter that's being passed into the method! How the heck does Ruby do that?!
I don't really know, so if you're reading this and you have an answer, please contact me and correct me!
Yes I know this sounds tedious, but honestly it'll drastically reduce the amount of time you spend being frustrated.
I usually try to keep it to one line and say something like:
- Begin first call of
recursive_method - Skip
if - Enter
else - read call to
recrusvie_methodsecond call - Pause first call
- Begin second call of
recursive_method - Enter
if - Return some value from second call of
recursive_method - End second call of
recursive_method - Unpause first call
...and so on like this.
Obviously on pen and paper I have the freedom to use arrows, and draw lines, and sort of make things take a different order. I encourage you to do whatever helps to wrap your mind around the topic!
See #1.
And...it's important to remember that it's possible for a method...with an if-else clause to return two different things, depending on if the if portion will be executed, or the else portion is executed.
And sometimes it's important to have either situation return the same thing...that is, have a return value placed outside the if-else clause...but still inside the method.
When writing things down, often times I was left wondering..."yes, i've reached the end of the second call....but what does Ruby do next?"
A method call will usually have a return value. Just like most everything in Ruby has some sort of return value. So will a call to a method inside itself. Often times that needs to be the solution, being passed from one, back up to the previous situation.
I don't really know if that'll help anyone else; However, these are some of the things that really helped me when trying to wrap my head around the topic of recursion.
And don't be intimidated by all the other information out there. Some of the people you're trying to learn from might not be as smart as you are....