21
$\begingroup$

A few use cases:

(1) This, as expected, returns (almost) immediately:

f[x_?NumericQ] := Evaluate[(Pause[1]; x)]
Plot[f[x], {x, 0, 1}]  

(2) This takes forever:

f[x_?NumericQ] := (Pause[1]; x);
Plot[f[x], {x, 0, 1}, Evaluated -> True]

(3) This is much faster than (1):

f[x_?NumericQ] := {(Pause[1]; x), x x};
Plot[f[x][[1]], {x, 0, 1}, Evaluated -> True]

(4) This returns immediately ... with a "wrong" plot:

f[x_?NumericQ] := {(Pause[a = x + 1]; a), x};
Plot[f[x][[1]], {x, 0, 1}, Evaluated -> True]

(5) While this, as expected, returns immediately, with the "right" plot:

f[x_?NumericQ] := Evaluate[(Pause[a = x + 1]; a)]
Plot[f[x], {x, 0, 1}]

I would like an "authoritative" explanation of cases (3) and (4) ... the rest I think I'm able to understand, but posted for completeness, and to get a complete answer that could be useful for others too.

$\endgroup$

1 Answer 1

19
$\begingroup$

If my understanding of it is correct, the evaluation sequence with Evaluated->True is as follows:

  • First, hide all external assignments to the iteration variables, in your case x (probably by using a Block[{x},...] construct).
  • Second, evaluate the expression without having an assignment to the iteration variables. Remember the resulting expression.
  • Third, assign values to the iteration variables as needed, and evaluate the expression obtained in the previous step for each value.

In your case (2), the expression with non-numeric x is inert, so the expression evaluated for each value of x is f[x] with numeric x, whose evaluation includes the Pause. That part you probably figured out yourself.

In your case (3), the expression to evaluate is f[x][[1]]. Again, f[x] is inert, so f[x][[1]] gives the first argument of f[x], which is x. So the expression to be evaluated is x, which of course is very fast; there's not even a call to f involved. Now it happens that your function, if called with a numeric value, would have returned a list with the value of x as a first element, so the plot you'd get with evaluating f on a numeric value and taking the first element would be the same. However that is just a coincidence, since your function is not even called.

In your case (4), the very same happens. Only this time you notice the difference, because the first element of the list your function returns no longer happens to be the value of the argument. Note that another way to see that your function has not been called is to evaluate a after the plot. Since your function assigns to a without protecting it with a scoping construct, after calling your function a should have a value of one more than the argument passed to f. However a remains unassigned, showing that your function was never called.

In your cases (1) and (5), the Evaluate only affects how f is defined, not the evaluation of f in Plot. Therefore there are no surprises. Basically, your definition in those cases is almost equivalent to if you had used = instead of := (it is not completely equivalent, but the difference doesn't matter for your code).

$\endgroup$
1
  • $\begingroup$ Very nice answer. Could you tell me something about how will Evaluated->False behave? or what's the difference between it with the default HoldAll attribute? PS: a typo in the first line: Evaluation->True should be Evaluated->True. $\endgroup$
    – luyuwuli
    Commented Sep 17, 2016 at 15:29

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.