4

Given a recursive function, is there some simple way to display or store the value of recursion or "how many levels deep" the function is at a given time?

For instance, if we wrote the recursive function to calculate the factorial of a number (for any positive integer x):

r[x_] := If[x > 0, x*r[x - 1], 1]

Is there some way to output, as the function evaluates that it is a level "n"?

Given that the $RecursionLimit determines the max number of times a function can call itself nested, there must be some flag or value stored to keep track of how deep the current evaluation is that is compared to $RecursionLimit, that, if exceeded, aborts. What is this flag/value?

Oleksandr R.
  • 23,023
  • 4
  • 87
  • 125
iwantmyphd
  • 901
  • 7
  • 13
  • 1
    From Stack documentation: "The maximum length of Stack[] is limited by $RecursionLimit." – Oleksandr R. Jan 18 '15 at 01:26
  • 1
    @Oleksandr The question how is (I believe) how can you access the present depth before $RecursionLimit is reached. – Mr.Wizard Jan 18 '15 at 01:29
  • 1
    @Mr.Wizard the documentation I quoted implies that the correct thing to do is Length@Stack[]. I am not sure if Stack[] is really the most fundamental manifestation of the evaluation stack, but even if not, I think it should suffice. Add StackBegin/StackInhibit to taste. – Oleksandr R. Jan 18 '15 at 01:32
  • @Oleksandr Okay, I missed that point. Thanks. Have you tested it? Can you help me find the earlier question? – Mr.Wizard Jan 18 '15 at 01:36
  • @Mr.Wizard http://stackoverflow.com/questions/7414601/memoized-recursive-functions-how-to-make-them-fool-proof/? I am not sure exactly which question you must be thinking of, but this seems close. – Oleksandr R. Jan 18 '15 at 01:49
  • @Oleksandr It is not the one I (think I) remember, but thank you. – Mr.Wizard Jan 18 '15 at 01:50
  • @Oleksandr It occurs to me that the subject of the question I remember may have been $IterationLimit rather than $RecursionLimit. Sorry if I wasted your time because of that, but I think the link you found is useful. – Mr.Wizard Jan 18 '15 at 01:53
  • @Oleksandr Yup, this is the one: (18397) – Mr.Wizard Jan 18 '15 at 01:54
  • @Oleksandr Are you planning to post an answer with Stack[]? I chose not to attempt this as I assumed you would. – Mr.Wizard Jan 21 '15 at 04:59
  • @Mr.Wizard I wasn't, as I can't really think of what to say beyond what the documentation gives us already. If you think you can do it justice, please go ahead. – Oleksandr R. Jan 22 '15 at 09:48
  • @OP could you please advise on whether or not the comments above have correctly understand the issue? If not then could you please expand on why Length@Stack[] is not what you are looking for? – Oleksandr R. Jan 25 '15 at 01:07

1 Answers1

4

The obvious way to modify your code is

Clear[f, r]
r[x_, n_] := If[x > 0, Print[n]; x*r[x - 1, n + 1], 1]
f[k_Integer /; k > 1] := r[k, 1]

For small values of x, this works fine.

f[5]

f[5]

But it is very inefficient and also limited by $RecursionLimit.

Block[{$RecursionLimit = 20}, f[24]]

aborted-f[24]

Both these issues can be addressed by using a less obvious tail-recursive version of r.

Clear[f, r]
r[0, val_, _] = val;
r[k_ /; k > 0, val_, n_] := r[k - 1, k val, Print[n]; n + 1]
f[k_Integer /; k > 0] := r[k - 1, k, 1]

Block[{$RecursionLimit = 20}, f[24]]

tail-f[24]

m_goldberg
  • 107,779
  • 16
  • 103
  • 257