Evaluation inside Inactivate

This statement from documentation might be misleading. It should be read in conjunction with first statement:

Inactivate[expr]

replaces all instances of f with Inactive[f] for symbols f used as heads in expr.

So Inactivate[expr, patt] really inactivates all symbols used as heads in expr, that match the pattern patt.

That's why in e.g. f[] expression f is inactivated:

ClearAll[f]
Inactivate[f[], f] // FullForm
(* Inactive[f][] *)

and in f expression - it's not:

Inactivate[f, f] // FullForm
(* f *)

In expression you passed to Inactivate:

Print /@ {1, 2} // Hold // FullForm
(* Hold[Map[Print, List[1, 2]]] *)

Print is not used as head of expression, so it's not inactivated.

Instead of Inactivate[Print/@{1,2}, Print] you could manually wrap Print with Inactive head:

Inactive[Print] /@ {1, 2} /. Inactivate@Print[a_] :> a // Activate
(* {1, 2} *)

jkuczm already explained your example, but pragmatically I think you may be looking for Block instead:

Block[{Flatten},
 Flatten /@ {1, {2, {3}}} /. Flatten[a_?AtomQ] :> a
]
{1, {2, 3}}

Of course there are other ways to perform this specific operation, e.g.

Flatten@*List @@@ {1, {2, {3}}}
{1, {2, 3}}

This one works because Apply does not modify atoms(1).


Note: Block may fail when using Packed Arrays, as some functions trigger low-level optimized code that Block does not affect. See:

  • Block attributes of Equal
  • Cannot Block Plus