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 aDoexpression: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 (aDoin this case) in my code.It's perhaps worth pointing out that
Hold[{1, 2, f[3, 4]}] //. f[x___] :> xreturns
Hold[{1, 2, Sequence[3, 4]}]so I can't easily implement a manual sequence-flattening step.
Answers
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_] := Internal`InheritedBlock[ {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.
Sequenceit might be easier $\endgroup$Sequenceat all. $\endgroup$inject[{aa -> {3, xx}}, Hold@With[{xx = 8}, Hold[{1, 2, aa}]]]$\endgroup$