0

Can anyone help me with how to understand the definition of the ExpandNCM function listed in the NonCommutativeMultiply documentation? Like, (h : NonCommutativeMultiply)[a___, b_Plus] for example. I do not understand how the parts of this expression relate to each other or what they accomplish.

The code in full, reproduced for convenience:

ExpandNCM[(h : NonCommutativeMultiply)[a___, b_Plus, c___]] := 
 Distribute[h[a, b, c], Plus, h, Plus, ExpandNCM[h[##]] &];
ExpandNCM[(h : NonCommutativeMultiply)[a___, b_Times, c___]] := 
 Most[b] ExpandNCM[h[a, Last[b], c]];
ExpandNCM[a_] := ExpandAll[a];

Thank you so much.

Oleksandr R.
  • 23,023
  • 4
  • 87
  • 125
Saesun Kim
  • 1,810
  • 13
  • 24

1 Answers1

5

First of all, you need to understand that, unlike most other languages, Mathematica is a term-rewriting system. This means that (at the top level) it is entirely based on patterns and transformation rules, not variables and values. When you write

x = 1;

it does not mean that a variable x is assigned the value 1. Rather, it instructs the system to apply a transformation rule that will cause the pattern x to be replaced with 1 wherever it appears in expressions. x is a very simple pattern that matches a literal x, but a great deal more flexibility is possible with patterns. This is what you see here.

All Mathematica expressions are built up from heads and arguments (the sequence of arguments is known as the body). A head is what appears before the brackets, and the arguments are what appear inside. This is more clear in the FullForm: for convenience, many expressions are written partially or completely in infix or postfix notation, but Mathematica does not work at this level. x = 1 is actually Set[x, 1], where Set is the head, and the arguments are x and 1. Every expression has exactly one head and zero or more arguments, and every part of an expression (head and each argument) is itself an expression. When there are zero arguments, it is a matter of choice to include the brackets or not--but this choice is part of the definition, so it must be done consistently.

When matching and transforming patterns, it is extremely useful to be able to name them, in order to re-use parts of the pattern in its replacement. If we write (h : Set)[x, 1], we have given the part of the pattern matching Set the name h. An application might be

x /: (h : Set)[x, 1] := h[z, 1]

which means that when x = 1 is seen, it is remembered that h on the left-hand side is to stand for Set on the right, and so the expression gets rewritten into z = 1:

x = 1;
x (* -> x *)
z (* -> 1 *)

(x /: lhs_ := rhs_ is the infix form of TagSetDelayed, which we use here to associate the transformation rule with x, rather than the protected system symbol Set.)

We can also name the arguments, or sequences constituting a number of them in succession, to use those in the same way. But, this question is about to be closed, so there isn't time to elaborate on that. Instead, I will just point you toward the documentation for Blank, BlankSequence, and BlankNullSequence.

Remember: everything in Mathematica is accomplished through pattern matching, so what you see here is not a set of definitions, but rather rewrite rules. Keep that in mind as you consult the documentation, and you should be able to understand it much more easily.

Oleksandr R.
  • 23,023
  • 4
  • 87
  • 125