Every expression in Mathics3 is built upon the same principle: it consists of a head and an arbitrary number of children, unless it is an atom, i.e. it can not be subdivided any further. To put it another way: everything is a function call. This can be best seen when displaying expressions in their “full form”:
FullForm[a + b + c]
Nested calculations are nested function calls:
FullForm[a + b * (c + d)]
Even lists are function calls of the function List
:
Head[{1, 2, 3}]
However, its full form is presented with {...}
FullForm[{1, 2, 3}]
The head of an expression can be determined with Head
:
Head[a + b + c]
The children of an expression can be accessed like list elements:
(a + b + c)[[2]]
The head is the 0th element:
(a + b + c)[[0]]
The head of an expression can be exchanged using the function Apply
:
Apply[g, f[x, y]]
Apply[Plus, a * b * c]
Apply
can be written using the operator @@
:
Times @@ {1, 2, 3, 4}
(This exchanges the head List
of {1, 2, 3, 4}
with Times
, and then the expression Times[1, 2, 3, 4]
is evaluated, yielding 24.)Apply
can also be applied on a certain level of an expression:
Apply[f, {{1, 2}, {3, 4}}, {1}]
Or even on a range of levels:
Apply[f, {{1, 2}, {3, 4}}, {0, 2}]
Apply
is similar to Map
(/@
):
Map[f, {1, 2, 3, 4}]
f /@ {{1, 2}, {3, 4}}
The atoms of Mathics3 are numbers, symbols, and strings. AtomQ
tests whether an expression is an atom:
AtomQ[5]
AtomQ[a + b]
The full form of rational and complex numbers looks like they were compound expressions:
FullForm[3 / 5]
FullForm[3 + 4 I]
However, they are still atoms, thus unaffected by applying functions, for instance:
f @@ Complex[3, 4]
Nevertheless, every atom has a head:
Head /@ {1, 1/2, 2.0, I, "a string", x}
The operator ===
tests whether two expressions are the same on a structural level:
3 === 3
3 == 3.0
But:
3 === 3.0
because 3
(an Integer
) and 3.0
(a Real
) are structurally different.