6
$\begingroup$

I discovered a strange behavior of the Evaluate function.

Case 1:

Clear[f]
f[x_] := x^2
g[x_] := Evaluate[D[f[x], x]]
Clear[f]
g[x]
2 x

Case 2:

Clear[f]
f[x_] := x^2
g[x_] := Evaluate[D[f[x], x]] + f[x]
Clear[f]
g[x]
f[x] + Derivative[1][f][x]

I think the Case 2 behavior is strange, because the derivative of f isn't evaluated properly when g defined.

Why do I see this difference?

$\endgroup$
6
  • $\begingroup$ Welcome to Mathematica.SE, thanks for taking the effort to state well formated question :) $\endgroup$
    – Kuba
    Commented May 15, 2014 at 14:17
  • $\begingroup$ Thank you for your quick and easy-to-understand reply! $\endgroup$ Commented May 15, 2014 at 14:22
  • $\begingroup$ I feel compelled to ask for the reopening of this question. I do not think it duplicates the question Mr.Wizard identifies as being duplicated. This question is about the explicit use of Evaluate at different levels of an expression and it's interaction with SetDelayed. The other question is about the explicit use of Evaluate and it's interaction with Function. For experienced Mathematica users, the two question are related, so it is no coincidence that part of Mr.Wizard's answer to the other question is applicable to this question. ... $\endgroup$
    – m_goldberg
    Commented May 16, 2014 at 1:28
  • $\begingroup$ ... But, despite the relationship, I assert that this question is sufficiently different that less experienced users, should they follow the link, will be more confused than enlightened. Should this question be reopened, I suggest the link to the other question be given in a comment. $\endgroup$
    – m_goldberg
    Commented May 16, 2014 at 1:29
  • $\begingroup$ @m_goldberg Okay, we'll try it your way. I posted a modified version of my original answer here. I await the community's feedback. $\endgroup$
    – Mr.Wizard
    Commented May 16, 2014 at 3:18

3 Answers 3

7
$\begingroup$

The reason is because Evaluate works only on the first level of held expression. Take a look:

You are using SetDelayed while creating g, it has Attribute HoldAll:

Attributes@SetDelayed
{HoldAll, Protected, SequenceHold}

so effectively, the right hand side of your definition is:

Hold[Evaluate[D[f[x], x]]] // FullForm (*first case*)
Hold[Derivative[1][f][x]]
Hold[Evaluate[D[f[x], x]] + 1] // FullForm (*second case*)
Hold[Plus[Evaluate[D[f[x],x]],1]]

As you can see, in the latter case Evaluate is deeper and is not going to work.

It is quite important issue and, imo, not stressed enough in documentation. You can read about it in PossibleIssues section of Evaluate.

$\endgroup$
2
  • $\begingroup$ It's also mentioned in the Details section. $\endgroup$ Commented May 15, 2014 at 14:26
  • $\begingroup$ @SjoerdC.deVries Agree, but that sentence is quite convolved for new users :) or at least it was for me ;) $\endgroup$
    – Kuba
    Commented May 15, 2014 at 14:34
2
$\begingroup$

Kuba explained what went wrong. This example will show you how to get the behavior you were probably expecting. Just use Set ( = ) instead of SetDelayed ( := ). This will get f evaluated at right time and will work for arbitrarily deeply nested calls to f.

Clear[f, g, h, x]
f[x_] := x^2
g[x_] = D[f[x], x] + f[x];
h[x_] = (1 + f[x]^3)/D[Log[f[x]], x];
Clear[f]
{g[x], h[x]}

{2 x + x^2, 1/2 x (1 + x^6)}

$\endgroup$
2
$\begingroup$

Evaluate only works when it is the explicit head of an argument. In other words Evaluate[ . . . ] must appear as one of the arguments of the Head who's Hold attribute you wish to override. You should read this paper, which teaches this among many other useful things:

As an example consider these lines:

Hold[1 + 1, Evaluate[2 + 2]]
Hold[1 + 1, {Evaluate[2 + 2]}]
Hold[1 + 1, Evaluate @@ {2 + 2}]
Hold[1 + 1, 4]

Hold[1 + 1, {Evaluate[2 + 2]}]

Hold[1 + 1, Evaluate @@ {2 + 2}]

Note that only the first form evaluates. On lines two and three the Heads of the second arguments are List and Apply rather than Evaluate.

In your example the outer function with a hold Attribute is SetDelayed rather than Hold, but the same logic applies.

A common method to get around this is to use With to inject an expression into the body of the definition:

Clear[f]
f[x_] := x^2

With[{body = D[f[x], x]},
  g[x_] := body + f[x]
]

Clear[f]
g[x]
2 x + f[x]

If you want to evaluate the entire right-hand-side, as in your first example, merely use Set instead of SetDelayed, and eliminate Evaluate:

Clear[f, g]
f[x_] := x^2

g[x_] = D[f[x], x];

Clear[f]
g[x]
2 x

(If this answer seems strangely familiar that's because it is; call this an experiment in following the advice to reopen.)

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.