20

Is there any way to completely remove the head of an expression function?

For example, how would I remove the head Cos from Cos[a] to give only a as an output.

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
Basheer Algohi
  • 19,917
  • 1
  • 31
  • 78
  • 4
    First@Cos[a]? – C. E. Jun 09 '14 at 00:03
  • 1
    Note that all expressions have heads and bodies. These two are not separable. For example, a has head Symbol. All you can do is to replace a head with something else or extract parts of an expression. – Oleksandr R. Jun 09 '14 at 00:50
  • @Oleksandr I agree and would think that the closest thing to a headless expression is one with Sequence as head. – acl Jun 09 '14 at 02:36
  • @MikeHoneychurch I was thinking about things like Sequence @@@ List[List[a, b], List[a, c]]. But you're right, for examples like in your answer Identity does the job. – acl Jun 09 '14 at 12:04

6 Answers6

27

You can actually Delete the head of the expression, which is part 0:

Delete[#, 0] & /@ {Cos[a], Sin[b], Tan[c]}
{a, b, c}

With version 10 operator forms:

Delete[0] /@ {Cos[a], Sin[b], Tan[c]}
{a, b, c}

One case of interest may be held expressions. If our expression is:

expr = HoldComplete[2 + 2];

And the head we wish to remove is Plus, we cannot use these:

Identity @@@ expr
Sequence @@@ expr
expr /. Plus -> Identity
expr /. Plus -> Sequence
Replace[expr, _[x__] :> x, 1]

All produce e.g.:

HoldComplete[Identity[2, 2]]  (* or Sequence *)

We can use Delete or FlattenAt:

Delete[expr, {1, 0}]
FlattenAt[expr, 1]
HoldComplete[2, 2]
HoldComplete[2, 2]

You could also use a pattern that includes the surrounding expression on the right-hand-side, as demonstrated here, e.g.:

expr /. h_[_[x__]] :> h[x]
HoldComplete[2, 2]

Notes

As the documentation for Delete reads:

Deleting the head of a whole expression makes the head be Sequence.

Delete[Cos[a], 0]
Sequence[a]

Since this resolves to a in normal evaluation this should usually not be an issue.

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
  • +1, I like my held expressions. About "when there is no surrounding expression", I like this remark. To see that this is really the behaviour of Delete, rather than some post-processing of the kernel, you can evaluate: SetAttributes[seqHHA, {SequenceHold, HoldAll}]; seqHHA@Evaluate@Delete[Cos[a], 0]. So I disagree with your latest edit. The "a whole expression" here is the entire first argument of Delete, rather than any "subexpression" of the expression in the first argument. – Jacob Akkerboom Jun 09 '14 at 09:46
  • @Jacob I'm not sure what your example is intended to illustrate, and I don't know why you disagree with what I said. In your case you Evaluate Delete[Cos[a], 0] before seqHHA sees it, so there is effectively no surrounding expression. What am I missing? – Mr.Wizard Jun 09 '14 at 09:51
  • @Jacob I just saw the addendum to your comment above, and I think I understand now, as well as I suppose what the documentation is saying. Nevertheless I don't think that (the documentation) is written very clearly. – Mr.Wizard Jun 09 '14 at 09:58
  • I agree that the documentation is not very clear. But such a mistake (of being vague) is easily made I guess :). I'm glad we looked at this, the behaviour of Delete w.r.t. generating Sequence has puzzled me before. – Jacob Akkerboom Jun 09 '14 at 10:02
  • 1
    @Jacob Would not your example be better written like this?: Attributes[seqHHA] = {SequenceHold}; seqHHA[Delete[Cos[a], 0]] – Mr.Wizard Jun 09 '14 at 10:17
  • 1
    I agree that that is better. It seems I was too cautious or something :). I think the HoldAll is irrelevant, but caution may be good. For example, Sequence[symb] may not resolve to symb if symb is intended to be a head, in for example Delete[{Sin},0][Pi]. Also compare this with ReleaseHold, i.e. ReleaseHold[Hold[Sin]][Pi]. – Jacob Akkerboom Jun 09 '14 at 11:51
10

Does this come close?

Cos[a] /. Cos[a] -> a

Or

Cos[a] /. _[a] -> a

Or

First@Cos[a]

Or

list = {Sin@a, Cos@b};
First /@ list

{a, b}

eldo
  • 67,911
  • 5
  • 60
  • 168
  • The second one is good because you can apply it to functions without need to retype the functions in Replace all. thanks eldo. – Basheer Algohi Jun 09 '14 at 00:11
  • @Algohi- see my update :) – eldo Jun 09 '14 at 00:17
  • 3
    Your second example doesn't remove the head, it just matches _[a] with literally a then always returns a. For example Cos[b] isn't matched. I guess you meant /. _[a___] -> a, so that eg lekker[b, c] /. _[a___] -> a works. – acl Jun 09 '14 at 00:25
  • @acl - Thanks - Just inspected the 4 forms by applying Head and FullForm to them - everything seems to be right. – eldo Jun 09 '14 at 00:33
  • 1
    Sorry, I did not mean that your examples don't work, but that if the argument is not a then it does not get matched, because the a on the right hand side of /. is not a pattern. eg Cos[b] /. _[a] -> a evaluates to Cos[b], ie, the a is matched literally. You probably meant Cos[b] /. _[a_] -> a or, more generally (allowing for multiple arguments) Cos[b] /. _[a___] -> a. – acl Jun 09 '14 at 00:40
  • @acl - ah ! now I got your interesting point. one can even write Cos[b] /. _@a___ -> a :) – eldo Jun 09 '14 at 00:45
10

You remove a head by replacing it with Identity

Cos[a] /. Cos -> Identity

For doing this over lots of expressions:

list = {ArcTan[x], ArcTan[x], ArcTan[x], Cot[x], Cot[z], Cot[x], 
  ArcTan[z], ArcTanh[y], ArcTanh[x], Cot[y]};

list[[All, 0]] = Identity

or

Identity @@@ list

etc

Mike Honeychurch
  • 37,541
  • 3
  • 85
  • 158
9

Sequence might be useful if your expressions come inside other expressions. For example:

num = 10;
lst = MapThread[
  #1@#2 &,
  {
   RandomChoice[{Cos, Sin, Exp, Tan, Cot, ArcTan, ArcTanh}, num],
   RandomChoice[{x, y, z}, num]
   }
  ]

(*

{ArcTan[x], ArcTan[x], ArcTan[x], Cot[x], Cot[z], Cot[x], ArcTan[z], 
 ArcTanh[y], ArcTanh[x], Cot[y]}

*)

(this is just a long-winded way of producing a list), then

Sequence @@ # & /@ lst

(*
{x, x, x, x, z, x, z, y, x, y}
*)

Roughly, Sequence dissolves and its children get promoted whenever it appears as something other than the topmost head, eg f[Sequence[g]] evaluates to f[g]. Thus,

expr = f @@ lst
Sequence @@ # & /@ expr

(*

f[ArcTan[x], ArcTan[x], ArcTan[x], Cot[x], Cot[z], Cot[x], ArcTan[z], 
 ArcTanh[y], ArcTanh[x], Cot[y]]

f[x, x, x, x, z, x, z, y, x, y]

*)
acl
  • 19,834
  • 3
  • 66
  • 91
4

I got same problem and did not find good answer here. Then I found Mathematica function Level is very usefull for this:

f=Cos[a];
Level[f, 1]

{a}

Second argument in level defines the depth of subexpressions to be extracted.

Level[Cos[a + b], 1]

gives you:

{a + b}

Meanwhile Level[cos[a + b], {-1}] completely opens subexpressions:

{a, b}

You strategy with more complex functions than just Cos[a] could be either to undestand and use proper levelspec parameter, or try to change it iteratively looking for your Head in the output list.

  • Actually, this replaced Cos by List. – bbgodfrey Sep 06 '16 at 23:16
  • 1
    Level can have a third argument, that can be used to put the result in something else other than List. For example, Level[Cos[a + b], {-1}, HoldComplete] or Level[Cos[a + b], {-1}, Sequence]. – Karsten7 Sep 07 '16 at 04:00
  • +1 as Level is very useful for getting a list of arguments. For example Level[Plus[a,b,c],1] which you can now Map, Select or something else without having the Plus remain as a head of the output. – Johu Sep 17 '18 at 02:05
1

One can also use DeleteCases (which also works inside held expressions):

DeleteCases[{Sin[Cos[x]], Cos[x], Hold[2 + 2], HoldComplete[2*3]}, 
 Cos | Plus | Times, -1, Heads -> True]

(*{Sin[x], x, Hold[2, 2], HoldComplete[2, 3]}*)
Basheer Algohi
  • 19,917
  • 1
  • 31
  • 78