# Injecting a sequence of expressions into a held expression

Consider the following toy example:

Hold[{1, 2, x}] /. x -> Sequence[3, 4]


It will give

Hold[{1, 2, Sequence[3, 4]}]


because Sequence[] (like Unevaluated) is expanded only in the first level of heads with attribute HoldAll.

How can I obtain Hold[{1,2,3,4}]? What is the simplest way to do this?

Notes:

• Use case: I am trying to generate a piece of code that will be passed to Compile. I need to inject a variable number of iterators (which I have as a list) into a Do expression:

Hold[Do[code, iterators]] /. iterators -> Sequence[{i,5}, {j,5}]

• I would prefers solutions that don't match on the expression enclosing x. I would not like to repeat this expression (a Do in this case) in my code.

• It's perhaps worth pointing out that

Hold[{1, 2, f[3, 4]}] //. f[x___] :> x


returns

Hold[{1, 2, Sequence[3, 4]}]


so I can't easily implement a manual sequence-flattening step.

Based on Leonid's code we can write a flattenSequence[] function that will flatten out all Sequence expressions at any level:

flattenSequence[expr_] :=
expr //. f_[left___, Verbatim[Sequence][middle___], right___] :>
f[left, middle, right]

flattenSequence[Hold[{1, Sequence[2, 3]}]]

(* ==> Hold[{1, 2, 3}] *)


Based on Mr.Wizard's code we can write a general function for injecting subexpressions into other expressions while supporting Sequence:

ClearAll[inject1, inject]

SetAttributes[inject1, HoldFirst]
Quiet[
inject1[expr_, (Rule|RuleDelayed)[var_Symbol, values : Verbatim[Sequence][__]]] :=
Replace[Unevaluated[values], Sequence[var__] :> expr];
inject1[expr_, (Rule|RuleDelayed)[var_Symbol, value_]] :=
Replace[Unevaluated[value], var_ :> expr],

{RuleDelayed::rhs}
]

SetAttributes[inject, HoldAll]
inject[rules_, expr_] :=
InternalInheritedBlock[
{Rule, RuleDelayed},
SetAttributes[{Rule, RuleDelayed}, HoldFirst];
ReleaseHold@Fold[inject1, HoldComplete[expr], rules]
]


Usage:

inject[{a -> Sequence[b, 3], b :> 1 + 1}, Hold[{a, b}]]

(* ==> Hold[{1 + 1, 3, 1 + 1}] *)


The replacements are done one after the other, so the second one can use the result of the first. Rule and RuleDelayed are both handled correctly.

-
If you don't insist on Sequence it might be easier –  acl Feb 17 '12 at 18:43
If you can solve this in a direct and robust way I think it will call into question the need for Sequence at all. –  Mr.Wizard Feb 17 '12 at 19:22
I just read this. You have plenty of answers already. I just wanted to point out that those answers that rely on building the expression on the rhs of a rule, such as the firsts of MrWizard, respect scoping so you can get things renamed if you are injecting inside a scoping construct. This means that your inject might too. Try inject[{aa -> {3, xx}}, Hold@With[{xx = 8}, Hold[{1, 2, aa}]]] –  Rojo Jul 17 '12 at 13:49

{3, 4} /. {x__} :> Hold[{1, 2, x}]

Hold[{1, 2, 3, 4}]


Leonid Shifrin used this here long before I wrote this answer.

In light of Leonid's comment to halirutan it is worth pointing out that you can inject expressions from an arbitrary head including Hold. You can also use -> rather than :> like this:

expr = Hold[{1, 2, x}];

Hold[6/2, 2 + 2] /. _[x__] -> expr

Hold[{1, 2, 6/2, 2 + 2}]

-
very cool actually –  acl Feb 17 '12 at 20:30
@acl I lied though: it still uses Sequence, just in the form of BlankSequence. halirutan uses SlotSequence. So I think it is not possible without Sequence of one brand or another. –  Mr.Wizard Feb 17 '12 at 20:32
Yes, but that's beyond the point. One could also do all this by converting to strings and replacing, and to me the other answers seem almost as clumsy as that. You do it with a much lighter touch. –  acl Feb 17 '12 at 20:36
@Kuba Pardon me, what? –  Mr.Wizard Mar 6 at 5:48
@Kuba This is not an injection but rather a replacement so it is not quite the same as this question. I think Leonid's method is probably the most applicable, e.g. If[Hold[{a, b}], If[Hold[{c, d}], e]] //. h_[x___, _[{y___}], z___] :> h[x, y, z]. The //. is not efficient on long expressions but handling that will make this longer, making other methods comparatively more attractive. –  Mr.Wizard Mar 6 at 5:57

ClearAll[inject];
SetAttributes[inject, HoldRest];
inject[Hold[{args__}], new__] := Hold[{args, new}]


This will also accept Sequence[3,4] as a second argument. Sequences are spliced, while arguments themselves not evaluated.

EDIT

You can also use a composite rule, with some head s instead of Sequence (you can localize s if needed):

Hold[{1, 2, x}] /. x -> s[3, 4] /.
f_[left___, s[middle___], right___] :> f[left, middle, right]

-
This is exactly what I meant when I said "I would prefers solutions that don't match on the expression enclosing x. I would not like to repeat this expression (a Do in this case) in my code." This will be ugly with the Do. –  Szabolcs Feb 17 '12 at 19:58
@Szabolcs Does my update address you needs? You could also wrap s around your Sequence, if you naturally get your results as a Sequence –  Leonid Shifrin Feb 17 '12 at 20:07
Yes, it does. This can be expanded into a function that will flatten out all Sequence elements in an arbitrary held expression (i.e. it can made into a self-contained and general tool that integrates well with other solutions) –  Szabolcs Feb 17 '12 at 21:08

One way is to use Function and the possibility of SlotSequence. I define an additional function f to be sure nothing gets evaluated:

f[x_] := Print["Evaluated"];
Function[Hold[Do[f[1], ##]]][{i, 5}, {j, 5}]

(*
Hold[Do[f[1], {i, 5}, {j, 5}]]
*)

-
This will have a problem when i or j have values before evaluation. You can use Function[Null,Hold[Do[f[1],##]],HoldAll] to avoid it. –  Leonid Shifrin Feb 17 '12 at 19:59

Not sure how robust this is, but you could do something like

flattenSequence[expr_, {x_, p__}] := Module[{f, t},
f[t__] = expr /. x -> t;
f[p]]


Then for the example above

flattenSequence[Hold[{1, 2, x}], {x, 3, 4}]

Hold[{1, 2, 3, 4}]

-

Neat solutions provided, but there are probably more straight forward ways to solve the original problem. One of these might help.

In:= s=0; Apply[Do[s+=i^i,{i,##}]&,Hold[1,12,3]]; s

Out[75]= 10000823800

In:= r=Hold[s=0;{1,12,3};s];
Part[r,1,2,0]=(Do[s+=i^i,{i,##}]&); ReleaseHold[r]

Out= 10000823800

-

Perhaps something like this?

ClearAll[replaceFlatteningSequences];
replaceFlatteningSequences[lhs_, pat_ :> rhs_] /; MatchQ[lhs, pat] :=
lhs /. lhs -> rhs
replaceFlatteningSequences[lhs_, pat_ :> Sequence[repSeq__]] :=
Module[{tag},
lhs /. {Slot -> tag, SlotSequence -> tag["Sequence"],
Function -> tag["Function"]} /. pat :> ## /.
all_ :> (all &[repSeq]) /. {tag["Function"] -> Function,
tag["Sequence"] -> SlotSequence} /. tag -> Slot
]


To be used

replaceFlatteningSequences[Hold@With[{x = 8}, ## aa &],
aa :> Sequence[x, 4]]


Hold[With[{x = 8}, ##1 x 4 &]]

-

In a previous answer Mr.Wizard suggested

Hold[1 + 1, 2 + 2, #] &@Unevaluated[3 + 3, 4 + 4]


However injecting deeper inside a Hold with this technique does not work:

Hold[{1 + 1, 2 + 2, #}] &@Unevaluated[3 + 3, 4 + 4]


returns Hold[{1 + 1, 2 + 2, Sequence[3 + 3, 4 + 4]}].

I would like to point out that a little variation does indeed work:

Hold[{1 + 1, 2 + 2, ##}] &[3 + 3, 4 + 4]


And if one does indeed want the arguments not to be evaluated, then it is possible to use

Function[Null, Hold[{1 + 1, 2 + 2, SlotSequence[1]}], {HoldAll}][3 + 3, 4 + 4]

-

I remarked before that I didn't think this was possible without Sequence, SlotSequence, BlankSequence, etc. (Without using string processing or the like that is.) It seems I was wrong, unless there is an implicit Sequence in here:

Hold[1 + 1, 2 + 2, #] & @ Unevaluated[3 + 3, 4 + 4]

Hold[1 + 1, 2 + 2, 3 + 3, 4 + 4]

-
This works fine because you are injecting at first level inside Hold. See my following answer for clarifications. –  Federico Mar 22 '13 at 23:05
Indeed, there is an implicit Sequence: try {#}&@Unevaluated[1, 2] // Trace. –  Federico Aug 4 at 17:22
@Federico I have this vague memory that I saw that in the trace when I posted this but that I did not consider it a "real" Sequence since it appears later? I don't know, and I haven't given this a lot of thought since then. Anyway, thanks for noting that for future readers. –  Mr.Wizard Aug 5 at 5:04

I though it is nice untill I had to add reparse function :)

SetAttributes[mySequence, HoldAllComplete];
mySequence[args__] := RawBoxes[  MakeBoxes[{args}][[1, 2]]  ];
reparse = ToExpression @* FrontEndExecute @* FrontEndReparseBoxStructurePacket @* ToBoxes

y = 7;
Hold[{1, x, 2, x, 3}] /. x :> RuleCondition @ mySequence[y, 1+2] //reparse

 Hold[{1, y, 1 + 2, 2, y, 1 + 2, 3}]

-
But the result is not that expression, it just looks like that expression. It cannot be re-used programmatically, and the produced cell cannot even be edited manually within the front end, then evaluated, without producing errors. –  Szabolcs Aug 4 at 10:53
@Szabolcs good point, fixed. but it is not so clean now :( –  Kuba Aug 4 at 11:06