10
$\begingroup$

Consider the following expression:

expr = Hold[
   {
    f[
     {1, {Print@1}}
     ],
    g[
     {{{Print@1}}}
     ]
    }
   ];

I'm looking for a way to apply a replacement rule to the contents of all expressions with head f. To give a more concrete example, let's say I want to replace Print by Echo, but only inside f.

Restrictions: I have no knowledge about the exact structure around and inside f - there could be more or less nesting going on. This means the replacement rule can't capture the wrapper with Hold attribute, nor can it capture the individual parts of f[…]. (And the evaluation of Print should be prevented of course)

$\endgroup$

3 Answers 3

11
$\begingroup$

Here's a way making use of Block to cause f to be inert:

Block[{f},
 SetAttributes[f, HoldAllComplete];
 expr /. f[args__] :>
   RuleCondition[f[args] /. Print -> Echo]
 ]

Hold[{f[{1, {Echo[1]}}], g[{{{Print[1]}}}]}]

Note of course that this only works if you have a pattern of the form _Symbol[...]

$\endgroup$
8
$\begingroup$

Alternatively:

expr /. 
  foo_f :> RuleCondition[Hold[foo] /. Print -> Echo] /. 
  Hold[foo_f] :> foo 

We can safely perform the second replacement because we just wrapped every f[..] with Hold.

$\endgroup$
2
  • $\begingroup$ +1 - In general, this is definitely better than my solution - the only potential issue is the fact that the pattern _f has to be written twice - so for complex patterns, this might lead to some code-duplication/performance cost $\endgroup$
    – Lukas Lang
    Jan 7, 2019 at 9:18
  • $\begingroup$ @LukasLang yes, consider this a quick solution to a specific problem. In general something like b3m2a1 shows is needed or a dummy vanishing head. $\endgroup$
    – Kuba
    Jan 7, 2019 at 9:21
8
$\begingroup$

[Edit: For most situations, @Kuba's answer is better]

I can think of one (ugly) way to do it:

Attributes[myHold] = {HoldAll};

expr /.
 f[args__] :> With[
   {res = myHold[args] /. Print -> Echo},
   f @@ res /; True
 ] /.
  HoldPattern[f_ @@ myHold[args__]] :> f[args]
(* Hold[{f[{1, {Echo[1]}}], g[{{{Print[1]}}}]}] *)

The idea is to wrap the contents of f inside a function with HoldAll attribute (not Hold, to be able to identify it uniquely later on). In a first step, the expression is returned with myHold[…] still in place. In a second round of replacements, myHold is stripped out again.

$\endgroup$
1
  • 3
    $\begingroup$ +1. If we use the vanishing macro defined in (43096), we can write vanishing[{h}, expr /. x_f :> RuleCondition[h[x] /. Print -> Echo]]. $\endgroup$
    – WReach
    Jan 5, 2019 at 18:16

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.