5
{x, x^2, Length@x, Subsets[x]} /. x -> {1, 2, 3}   
(* {{1, 2, 3}, {1, 4, 9}, 0, {{}, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}}} *)

with error enter image description here

What does it mean?

Why ^ evaluates, but Length not?

Why there is correct result of Subsets in output, but raised error?


UPD:
Many thanks to all for the detailed explanations!
Still the question was interesting

lesobrod
  • 1,657
  • 9
  • 14
  • Length evaluates to be 0; check Length@x. Not sure what you mean when you say it does not evaluate. Also, the argument of Subset has to be a list, and currently it is not, hence the error. – bmf Feb 24 '23 at 10:09
  • 2
    I don't understand. Does Length and Subsets evaluate after replacement? Then x will be List! And why we see right result of Subsets? – lesobrod Feb 24 '23 at 10:11
  • Why should they evaluate after the replacement? I just explained with the example; Length@x gives 0. Is it possible that you want to write foo[n_] := {x, x^2, Length@Range@n, Subsets[Range@n]} /. x -> Range@n and then foo[3]? – bmf Feb 24 '23 at 10:12
  • 1
    No need to be reopen, but reasons for close "is unlikely to help any future visitors, or else it is easily found in the documentation" is absolutely unconvincing. – lesobrod Feb 25 '23 at 19:03

2 Answers2

7

Let me repeat again:

If a function doesn't have a HoldAll/HoldFirst/HoldRest/HoldAllComplete attribute, its argument(s) will always be evaluated before going into the function.

ReplaceAll (/.) doesn't have such attribute, so the whole {x, x^2, Length@x, Subsets[x]} evaluates before the replacement happens. (The order is from left to right, BTW. ) This can be checked with Trace:

Trace[{x, x^2, Length[x], Subsets[x]} /. x -> {1, 2, 3}]

enter image description here

If you want to check the evaluation of x and x^2, set TraceOriginal -> True, the output will be a bit more involved, though.

As we can see, Length@x evaluates to 0. This is expected. As mentioned in Details section of document of Length:

Length[expr] returns 0 whenever AtomQ[expr] is True.

Subsets[x] evaluates to itself with a warning Subsets::normal. Since the Subsets[x] is still there, once the replacement happens, it'll become Subsets[{1, 2, 3}] and further evaluates to the desired output.

Finally, in addition to the Hold & ReleaseHold technique shown in rhermans' answer, another (more advanced) way to adjust the evaluation order is to use Unevaluated:

Unevaluated@{x, x^2, Length[x], Subsets[x]} /. x -> {1, 2, 3}
(* {{1, 2, 3}, {1, 4, 9}, 3, {{}, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}}} *)
xzczd
  • 65,995
  • 9
  • 163
  • 468
  • +1, can you explain why Unevaluated is more advanced and how is different? – rhermans Feb 25 '23 at 09:08
  • 1
    @rhermans Unevaluated is a special function, it owns some properties that cannot be explained in usual way. A simple example: f[a][[1]] returns a, but Unevaluated[a][[1]] returns the input with a warning. I'd recommend reading this: https://library.wolfram.com/infocenter/Conferences/377/ Some other posts showing its special behavior: https://mathematica.stackexchange.com/q/110490/1871 https://mathematica.stackexchange.com/q/110499/1871 – xzczd Feb 25 '23 at 09:30
6

What's happening on your code

You can check the evaluation with TracePrint. You will see that the Left hand side does get evaluated before the replacement. At that first evaluation x^2 returns unchanged, Subsets[x] gives an error and also returns unchanged. Length[x] evaluates and returns 0.

TracePrint[
{x, x^2, Length@x, Subsets[x]} /. x -> {1, 2, 3}   
]

enter image description here

You could have investigated the error with Show Stack Trace.

enter image description here

enter image description here

One of many solutions to what you ask

You could avoid the left hand side been evaluated by using Hold and only ReleaseHold after ReplaceAll (/.) has evaluated. That will avoid the error from trying to evaluate Subsets[x] and have Length return the length of {1, 2, 3} (3) instead of the length of x (0).

ReleaseHold[
     Hold[{x, x^2, Length@x, Subsets[x]}] /. x -> {1, 2, 3}   
]

enter image description here

This does evaluate in the order you want

enter image description here

Answers

This is a rather abstract and advanced issue, it's ok to find it complicated. I struggled articulating a precise answer myself.

What does it mean?

It means you need to consider in which order thigs are evaluated, and how many times that happens. You can control that order in many ways. See Evaluation Control.

Why ^ evaluates, but Length not?

Both evaluate. Length[x] evaluates to 0. Power[x,2] evaluates but first returns unchanged, and remains unchanged until ReplaceAll evaluates changing x for {1,2,3}. Then Power[{1,2,3},2] evaluates to {1,4,9}.

Why there is correct result of Subsets in output, but raised error?

Because it first tries to evaluate Subsets[x], gives an error and returns unchanged. Then ReplaceAll evaluates, and now Subsets[{1, 2, 3}] can evaluate correctly and give an output different from the input.

rhermans
  • 36,518
  • 4
  • 57
  • 149
  • But why Power evaluates? – lesobrod Feb 24 '23 at 10:19
  • @lesobrod I have added further explanations. Does this answer your question now? – rhermans Feb 24 '23 at 11:15
  • "Power[x,2] remains unevaluated. " To be precise, it returns unevaluated i.e. the output is the same as the input. – xzczd Feb 24 '23 at 11:23
  • 2
    @xzczd I now have "Power[x,2] evaluates but returns unchanged, and remains unchanged until ReplaceAll evaluates.". Would you agree with that? Feel free to directly edit the text to make it more precise, if you wish . – rhermans Feb 24 '23 at 11:24
  • @rhermans This is exactly what I expected from community, thank you! – lesobrod Feb 24 '23 at 16:28