Mathematica Stack Exchange is a question and answer site for users of Mathematica. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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

tree1

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

tree2

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

share|improve this question
1  
Have you seen Variables. Try Variables@y instead. – Edmund Mar 25 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 at 13:12
up vote 4 down vote accepted

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]]

trace1

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]]]

trace2

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]]]

trace3

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.

share|improve this answer
    
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 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 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 at 14:19
    
@Kattern. Recommend David Wagner's book. See chapter 7. Free download from this question – m_goldberg Mar 25 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 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

enter image description here

var // RotateLeft // TreeForm

enter image description here

share|improve this answer
    
Sorry, I do not get the point here. – Kattern Mar 25 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 at 14:08
    
Using Variable in both ways does not return the results needed, but also thanks for the answer provided. – Kattern Mar 25 at 14:31
1  
Recommend that you clarify what you mean by "Free symbols". – Bob Hanlon Mar 25 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 at 14:37

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.