Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I have been working on picking expressions apart using Head and Part and encountered a little mystery. Consider the canonical example

a + b + c

which has FullForm

Plus[a, b, c]

We expect, then, (a+b+c)[[0]] === Plus === Head[a+b+c] to be True, and it is. But then, we would expect (a+b+c)[[1;;3]] would be {a, b, c}, wouldn't we? But it isn't. The following is true:

(a + b + c)[[1;;3]] === (a + b + c)

Somehow, [[1;;3]], which is supposed to pick off elements 1 through 3 of its argument and put them in a List, doesn't get rid of the Head, which is element 0!

The questions are, then (and I will be grateful for hints and answers!)

  1. Why doesn't (a + b + c)[[1;;3]] get rid of (a + b + c)[[0]], the Head?

  2. What is the right way to get rid of the Head?

  3. (a + b + c)[[0;;3]] produces 0. I would expect it to produce {Plus, a, b, c}. Instead, it produces 0. This just deepens the mystery for me! Why?

share|improve this question

2 Answers 2

up vote 44 down vote accepted

Point #1

Part always wraps element sequences with the original head of the expression.

expr = Hold[1 + 1, 2 + 2, 3 + 3, 4 + 4, 5 + 5];

expr[[{2, 3}]]
Hold[2 + 2, 3 + 3]

For this purpose a single part e.g. 1 is not a sequence but {1} and 1 ;; 1 are:

expr[[1]]

expr[[{1}]]

expr[[1 ;; 1]]
2

Hold[1 + 1]

Hold[1 + 1]

This applies at every level of the extraction:

expr = g[h[1, 2], i[3, 4]];

expr[[  2 , 1  ]]
expr[[ {2}, 1  ]]
expr[[  2 ,{1} ]]
expr[[ {2},{1} ]]
3

g[3]

i[3]

g[i[3]]

I used this nontrivially for Elegant manipulation of the variables list.

Point #2

Consider instead using Extract which wraps sequences in List:

Extract[expr, {{2}, {3}}]
{4, 6}

The third argument of Extract can be used to specify a function to apply to individual elements before they are evaluated:

Extract[expr, {{2}, {3}}, HoldForm]
{2 + 2, 3 + 3}

If you want all parts you can also use Level:

Level[(a + b + c), {1}, Heads -> True]
{Plus, a, b, c}

Or Cases:

Cases[(a + b + c), _, Heads -> True]
{Plus, a, b, c}

Or Replace/ReplaceAll:

(a + b + c) /. head_[body___] :> {head, body}
{Plus, a, b, c}

Point #3

The last point is more tricky and I had to check it myself. There is a behavior that I also did not expect:

Range[5][[0 ;; 5]]
{}

What I expected was an error as seen here:

Range[5][[0 ;; 4]]

and here:

Range[5][[0 ;; 6]]

When Span is used in Part[x, 0 ;; n] where n is the length of x, Part returns the head of the expression. Therefore (a + b + c)[[0;;3]] returns Plus[] and Plus[] evaluates to 0.


I believe Span behaves this way because of how it handles non-positive values, and zero-length spans. Consider:

Range[10][[-2 ;; 10]]
{9, 10}

You can see that it wraps around. Now consider:

Range[10][[5 ;; 4]]
{}

An empty span returns the head of the expression with no arguments.

Using 0 ;; n where n is the last element in the list, or 0 ;; -1, is also an empty span wrapping around the open end of the list.

Range[10][[0 ;; -1]]
{}
share|improve this answer
1  
Ah, I see that you can answer #1 as well, not just Leonid :) –  Verbeia Feb 29 '12 at 6:26
1  
Regarding point #3, you might find this discussion relevant (if not too enlightening). –  Szabolcs Feb 29 '12 at 11:47
    
@Szabolcs That's important information. I cannot recall a situation where it would affect me, but it would be bloody annoying to track it down if it did. –  Mr.Wizard Feb 29 '12 at 16:36
1  
And another place for the all-powerful Cases: Cases[{a + b + c}, head_[args___] -> {head, args}] produces {{Plus, a, b, c}} –  Reb.Cabin Mar 8 '12 at 23:04
2  
@Reb doing that route you don't even need Cases: a + b + c /. head_[args___] :> {head, args} –  Mr.Wizard Mar 9 '12 at 0:06

Perhaps only the developers (or Leonid) can answer #1 and #3 and "why".

The quick answer to #2 is Apply, remembering that List is a Head like any other:

List @@ (a + b + c)

{a, b, c}

On #3, I can't explain why ;; syntax gives 0 when

(a + b + c)[[Range[0, 3]]]

gives

a + b + c + Plus

So you could try

List @@ ((a + b + c)[[Range[0, 3]]])

{a, b, c, Plus}

share|improve this answer
    
There is something broken in the way the site previews answers. I have been amending my answer for the last twenty minutes and only now do I see that you also posted an answer. –  Mr.Wizard Feb 29 '12 at 6:48
    
@Mr.Wizard You don't get notified of a new answer when editing your already existing answer... –  rm -rf Feb 29 '12 at 8:15
1  
The List @@ answer has a deep, hackish charm, coming closest to answering "... and everything but Head.". The Extract and Level answers have more versatility and clearly enable complete analysis and compilation of expressions. A metacircular evaluator for MMA would not seem too remote a possibility. –  Reb.Cabin Feb 29 '12 at 8:17
    
@R.M I would expect that when you save the edit to your post, the page would refresh, showing any new answers that were posted while you were working. This is not the case. –  Mr.Wizard Feb 29 '12 at 16:35
    
In some sense, Sequence@@(a+b+c) comes closer to "everything but Head" than List@@(a+b+c): While List is just another head (with a special input/display syntax associated with it), Sequence is the closest Mathematica has to a headless expressions: If you insert it anywhere (except functions with attribute HoldAllComplete) it just gets interpolated. –  celtschk May 21 '12 at 19:35

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.