- When
f(x-1)
is called, is it callingf(x) = x+10
orf(x) = if ...
- Is this a tail recursion?
How should I rewrite it using static / dynamic allocation?
let fun f(x) = x + 10 in let fun f(x) = if x < 1 then 0 else f(x-1) in f(3) end end

- 15,635
- 1
- 41
- 66

- 1
- 1
1 Answers
Before addressing your questions, here are some observations about your code:
There are two functions
f
, one inside the other. They're different from one another.To lessen this confusion you can rename the inner function to
g
:let fun f(x) = x + 10 in let fun g(x) = if x < 1 then 0 else g(x-1) in g(3) end end
This clears up which function calls which by the following rules: The outer
f
is defined inside the outerin
-end
, but is immediately shadowed by the innerf
. So any reference tof
on the right-hand side of the innerfun f(x) = if ...
is shadowed becausefun
enables self-recursion. And any reference tof
within the innerin
-end
is shadowed
In the following tangential example the right-hand side of an inner declaration
f
does not shadow the outerf
if we were usingval
rather thanfun
:let fun f(x) = if (x mod 2 = 0) then x - 10 else x + 10 in let val f = fn x => f(x + 2) * 2 in f(3) end end
If the inner
f
is renamed tog
in this second piece of code, it'd look like:let fun f(x) = if (x mod 2 = 0) then x - 10 else x + 10 in let val g = fn x => f(x + 2) * 2 in g(3) end end
The important bit is that the
f(x + 2)
part was not rewritten intog(x + 2)
becauseval
means that references tof
are outerf
s, not thef
being defined, because aval
is not a self-recursive definition. So any reference to anf
within that definition would have to depend on it being available in the outer scope.But the
g(3)
bit is rewritten because betweenin
-end
, the innerf
(nowg
) is shadowing. So whether it's afun
or aval
does not matter with respect to the shadowing oflet
-in
-end
.(There are some more details wrt.
val rec
and the exact scope of alet val f = ...
that I haven't elaborated on.)
As for your questions,
You should be able to answer this now. A nice way to provide the answer is 1) rename the inner function for clarity, 2) evaluate the code by hand using substitution (one rewrite per line,
~>
denoting a rewrite, so I don't mean an SML operator here).Here's an example of how it'd look with my second example (not your code):
g(3) ~> (fn x => f(x + 2) * 2)(3) ~> f(3 + 2) * 2 ~> f(5) * 2 ~> (if (5 mod 2 = 0) then 5 - 10 else 5 + 10) * 2 ~> (if (1 = 0) then 5 - 10 else 5 + 10) * 2 ~> (5 + 10) * 2 ~> 15 * 2 ~> 30
Your evaluation by hand would look different and possibly conclude differently.
What is tail recursion? Provide a definition and ask if your code satisfies that definition.
- I'm not sure what you mean by rewriting it using static / dynamic allocation. You'll have to elaborate.

- 15,635
- 1
- 41
- 66