A number of functions provide for results to be wrapped in an arbitrary head. This is very important in cases where the results should not be evaluated. Take Level as an example:

expr = Hold[{2/2, g[8/4], 1/0}];

Level[expr, {-2}, Hold]
Hold[1/2, 1/4, 1/0]

Cases however provides no such parameter, causing undesired evaluation:

Cases[expr, _Times, 3]

Power::infy: Infinite expression 1/0 encountered. >>

{1, 2, ComplexInfinity}  (* failure *)

How can this behavior be attained?


1 Answer 1


The best I have is manual RHS holding and Join, after which an arbitrary head could be Applied:

Join @@ Cases[expr, x : _Times :> Hold[x], 3]
Hold[2/2, 8/4, 1/0]

This could be done automatically as follows:

makeHeld[(L_ -> R_) | (L_ :> R_)] := L :> HoldComplete[R];
makeHeld[pat_] := x : pat :> HoldComplete[x];

heldCases[expr_, rule_, args___] :=
 Join @@ Cases[Unevaluated @ expr, makeHeld @ rule, args]

I am now reasonably happy with this but I still wonder if there is a more elegant or efficient method.

For fun here is a one-line definition of makeHeld using "vanishing patterns" and Part properties:

makeHeld[(L_ -> R_) | (L_ :> R_) | L_] := x : L -> HoldComplete[R, x][[{1}]];

It's not quite as efficient and clarity suffers so I won't replace the version above with it.

  • $\begingroup$ +1. I don't know why you dislike the code, it looks pretty good to me. Just one thing - I'd use Cases[Unevaluated[expr], Replace[...],args]. $\endgroup$ Sep 6, 2013 at 6:59
  • $\begingroup$ @Leonid I'm glad it looks good. I guess it just seems like a lot of code for what I think is a rather obvious omission from Cases syntax. Unevaluated[expr] does make sense regarding the name holdCases but it was my intent instead to implement this as if it was a parameter of Cases, just as it is for Level, and Cases does not have HoldFirst. $\endgroup$
    – Mr.Wizard
    Sep 6, 2013 at 7:02
  • $\begingroup$ @Leonid I changed the code somewhat; I think it's easier to read and a bit more efficient. Do you agree/confirm? $\endgroup$
    – Mr.Wizard
    Sep 6, 2013 at 7:22
  • 1
    $\begingroup$ @Mr.Wizard The reason I suggested Unevaluated is that otherwise the expression will evaluate, once passed to heldCases, even when you wrap it in one level of Unevaluated, because there is a rewrite step heldCases to Cases. In other words, when I need to destructure an expression while keeping it unevaluated, I use Cases[Unevaluated[expr],...], while doing the same with heldCases as heldCases[Unevaluated[expr],... won't work with your current code. Re: rewrite - quite nice, I agree. $\endgroup$ Sep 6, 2013 at 10:49
  • 1
    $\begingroup$ @rcollyer x := godObject["rcollyer", "confusticate"] -- meet me in chat ;-) $\endgroup$
    – Mr.Wizard
    Sep 6, 2013 at 12:59

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.