What is primary, function computation or function application?
We can use some of Mathematica's built-in tracing facilities to help us answer this question.
Let's start by ensuring that the symbols we are about to use carry no extraneous definitions:
ClearAll[f, g, x]
Now, we'll establish the definitions from the question:
g[x_] := x^2
f[x_] := Sqrt[g[x]]
We can turn on selective tracing of some functions to see what is going on:
On[f, g, Sqrt]
Now, let's evaluate f
for several values (here only 3 instead of 100 to keep the output manageable):
Map[f, Range[3]]
This shows us that f
and g
are being evaluated from first principles for each value in the range.
Should we wish to evaluate f[x]
only once, applying the resultant expression to each value, then we must do something like this:
Map[Function[{x}, Evaluate@f[x]], Range[3]]
The expression defines an anonymous function of x, whose body is the result of evaluating f[x]
. It is very important that x
has no value at this point -- that is why we cleared it at the beginning. Having done that, we can now see that f
and g
were only evaluated for x
instead of for every range value.
Incidentally, observe that f[x]
ultimately evaluates to Sqrt[x^2]
rather than x
since Mathematica does not assume that x
can only be a positive real number.
The syntax used in the preceding example can be abbreviated if we use so-called "slot" notation (#
):
Map[Evaluate@f[#] &, Range[3]]
Again, we can see that f
and g
are not evaluated for each range element. The slot reference #1
has taken the place of the named variable x
from the previous example.
Once we have completed our analysis, and are tired of seeing all those trace messages, we can turn off tracing like this:
Off[]
Note that you are using :=
, also known by its FullForm
name SetDelayed
, to define your functions. According to the Documentation Center page for :=
:
lhs := rhs
assignsrhs
to be the delayed value oflhs
.rhs
is maintained in an unevaluated form. Whenlhs
appears, it is replaced byrhs
, evaluated afresh each time.
This means that Sqrt[g[x]]
is maintained in an unevaluated form, meaning that the latter case of your first question is how the calculation works internally; in other words, it does not conclude $f(x)=x$. More importantly, it doesn't even look at Sqrt[g[x]]
, except to store it as a definition.
As an additional example, consider the following:
h[x_] := Pause[1];
The definition proceeds instantly, which indicates that Mathematica doesn't even touch the definition. However, executing h[x]
takes one second.
For your second question, in general it is not possible to conclude $\sqrt{x^2}=x$, unless $x$ is real and nonnegative. You can force it to use such an assumption as follows:
Refine[f[x], x > 0]
(*x*)
Like k_v also proposed Refine
can be used.
ClearAll[f, g, h];
g[x_] := x^2;
f[x_] := Sqrt[g[x]];
h[x_] = Block[{x}, Refine[f[x], x > 0]];
Trace@Map[h, Range[100]]
h[x]===x
returns True