Preamble
I will use this question as a pretext to demonstrate a more complex and powerful version of an injector pattern. I have been profitably using it for a while now, starting long before this pattern got its current name, but it seems like this powerful generalization is still widely unknown, while being often quite useful.
Nested injector pattern
The essence of nested injector pattern is that sometimes we need to inject more than one different piece of code in a single go. But a simple injector pattern does not allow it. The nested injector pattern allows one to accumulate several such expressions by using nested rules. As an example, I will use a task I faced recently while preparing this answer. To be specific, we may start with held code like this:
Hold[n + n^2*f[n - 1]]
and need to end up with a code like this:
Hold[f[n - 1, n + n^2*# &]]
following these steps:
- hunt the code for
f[x___]
- replace all such entries with
Slot
(#
)
- convert the held code inside
Hold
to a pure function
- construct a call to
f
with this pure function as a second argument
While this can be done step by step, in the straightforward implementation of this strategy we won't be able to reuse expressions found at intermediate steps for each of the steps outlined, and the resulting code will be much heavier and less elegant.
Here is the code adopted from the answer I linked to, which does implement this strategy using a nested injector pattern:
Cases[
heldBody,
p : _f :>
(Hold[p] /. Hold[f[x___]] :>
(heldBody /. HoldPattern[p] -> # /. Hold[code_] :>
Hold[f[x, Function[code]]])),
Infinity,
1
]
If you look carefully at the nested rule in it, you will see how nested injector pattern works. First, we find an entry which matches _f
(this is done by Cases
). The rule wraps it in Hold
and then uses a one-level injector pattern:
Hold[p] /. Hold[f[x___]] :> ...
But instead of directly injecting x
somewhere, we use another one-level injector pattern inside:
(Hold[p] /. Hold[f[x___]] :>
((heldBody /. HoldPattern[p] -> #) /. Hold[code_] :> ...
transforming heldBody
as heldBody /. HoldPattern[p] -> #
along the way. Note that this intermediate transformation makes use of p
which was found dynamically in this same rule application, just earlier. Now, apart from this transformation which we needed, if you look at entire rule you will notice that by using a (in this case) double-injector pattern, the rule was able to collect two different pieces of unevaluated code in one go (x
and code
)
p : _f :>
(Hold[p] /. Hold[f[x___]] :>
(heldBody /. HoldPattern[p] -> # /. Hold[code_] :>
Hold[f[x, Function[code]]]))
and inject them in proper places.
There is no limit to how many different code pieces you may be able to collect with this technique, you will just need to make use of an n
-level injector pattern if you need n
pieces of code. At some point, this may hurt readability though, so perhaps some balance is needed, and if you need too many, it may mean that you have to write a proper parser.
The case at hand
In the case at hand, here is a double-injector pattern that does the job:
{a_, b_, c_} /. {patt__} :>
(Hold[a, b, c] /. Hold[args___] :>
SetDelayed @@ Hold[int[patt], NIntegrate[f[args], {x, 0, 1}]])
I used SetDelayed @@ Hold[lhs, rhs]
pattern to avoid variable renaming.