Free symbols in an expression

I am starting to learn the basic MMA grammar these days. I hope I do not ask too much stupid questions. Here is one of them:

Getting free symbols in an expression can be done by following codes:

x = a + b;
y = x*x + x*c + d;
DeleteDuplicates@Cases[y, _Symbol, -1]

> {a, b, c, d}


These is no problem yet. The problem comes when the expression comes with Hold, HoldForm or Defer.

y = Defer[x*x] + x*c + d;
DeleteDuplicates@Cases[y, _Symbol, -1]

> {a, b, c, d, a + b}

y // TreeForm


The part I do not understand is Cases return a+b as free symbol, but TreeForm has a leaf of x. How to interpolate these outpus. To make the question even intersting, consider:

y = Defer[x*x] + HoldForm[x*c] + d;
DeleteDuplicates@Cases[y, _Symbol, -1]

> {d, a + b, c}

y // TreeForm


If I want the free symbol as shown in TreeForm, which is c, d, x in the last example. What should I input?

• Have you seen Variables. Try Variables@y instead. – Edmund Mar 25 '16 at 12:46
• @Edmund Thanks, Variables is promising, but it cannot totally solve this problem, it only works for polynomial. Therefore, for general expression it won't work. E.g.  Defer[x*x] + HoldForm[Sin[x]*c] + d. – Kattern Mar 25 '16 at 13:12

Your problem has little to do with Hold or any of its cousins. It has to do with the evaluator recursively evaluating symbols until it gets no changes. This can be demonstrated by using Trace.

x = a + b;
y = Hold[x*x] + x*c + d;
Trace[DeleteDuplicates @ Cases[y, _Symbol, -1]]


Note that Cases returned {a, b, c, d, x, x}, but then x got evaluated in the argument sequence passed to DeleteDuplicates, producing the result you don't want.

To get what you want you could do the following, using Block to locally make x a free variable.

x = a + b;
y = Hold[x*x] + Hold[x]*c + d;
Block[{x},
Trace[DeleteDuplicates@ Cases[y, _Symbol, -1]]]


But consider that if you assign y within the block, you don't need to worry about Hold.

x = a + b;
Block[{x},
y = x*x + x*c + d;
Trace[DeleteDuplicates @ Cases[y, _Symbol, -1]]]


Update 1

As to why

 y = Hold[x*x] + Hold[x]*c + d;
Cases[y, _Symbol, {-1}]


produces

{d, c, a + b, a + b, a + b}

rather than

{d, c, x, x, x}

This has a simple explanation. Cases actually returns {d, c, x, x, x}, but recall this is the short form for List[d, c, x, x, x]. Now List is function (although you may be thinking of it as a data type), so the evaluator evaluates this function call as well any other. The 2nd step in the evaluation cycle is to evaluate the function's argument, so of course x gets evaluated.

Update 2

After thinking this over for a while, it occurred to me that you might be interested in another approach to restricting evaluation. This will give a display form that meets your requirements.

y = ReleaseHold[Hold[x*x + x*c + d] /. HoldPattern[s : x | c | d] -> HoldForm[s]]


d + c x + x^2

y can still be evaluated with

y // ReleaseHold


(a + b)^2 + (a + b) c + d

but now

result = DeleteDuplicates @ Cases[y, HoldForm[_], {-2}]


gives

{d, c, x}

However, remember this is for display only. The internal form is

result // FullForm


List[HoldForm[d], HoldForm[c], HoldForm[x]]

Like y, result can be evaluated with ReleaseHold.

• Is this mean there is nothing we can do to prevent the result from Case evaluated, unless put x into a local scope? Trace@Cases[y, _Symbol, -1] will also evaluate the result. – Kattern Mar 25 '16 at 14:00
• I find evaluation of expression is not easy to understand. Could you please provide me some links on this topic? The documentation is a little confusing. – Kattern Mar 25 '16 at 14:05
• @Kattern. If a variable bound to value, i.e., has an own-value in a given scope, the easy way to make the evaluator ignore that binding is to put the variable into a scope where it isn't bound. – m_goldberg Mar 25 '16 at 14:19
• @Kattern. Recommend David Wagner's book. See chapter 7. Free download from this question – m_goldberg Mar 25 '16 at 14:20
• The local scope part I can understand. I just do not know whether we can defer the evaluation for result of Cases[y, _Symbol, -1]. Because the result is also evaluated for Cases[y, _Symbol, -1]. – Kattern Mar 25 '16 at 14:23
x = a + b;

y = Defer[x*x + g] + 6 x*c + Pi*d + Sin[a*E];

Variables@Level[y, {-1}]

(*  {a, b, c, d, g}  *)

Variables@Cases[y, _Symbol, -1]

(*  {a, b, c, d, g}  *)


EDIT:

y = Defer[x*x] + HoldForm[x*c] + d;

var = Cases[y,
z_Symbol?(! NumericQ[#] &) :> If[AtomQ[z], z, HoldForm[z]], -1] //
Union


var // RotateLeft // TreeForm


• Sorry, I do not get the point here. – Kattern Mar 25 '16 at 14:00
• In a comment, Edmund suggested using Variable. You replied in a comment that it only worked with polynomials. This shows that that you can readily get a list of the variables with Variable. I show two different ways. – Bob Hanlon Mar 25 '16 at 14:08
• Using Variable in both ways does not return the results needed, but also thanks for the answer provided. – Kattern Mar 25 '16 at 14:31
• Recommend that you clarify what you mean by "Free symbols". – Bob Hanlon Mar 25 '16 at 14:34
• I understand what you are talking about, but I do not have a suitable name for what I want. Sorry for the inconvenience caused. Do you have any suggestion on how to name what I want in the question? – Kattern Mar 25 '16 at 14:37