The question I have is, where can I learn this stuff? Where can I learn how exactly the parser works? Where can I learn exactly how compound expressions work?
The challenges you describe are very common for folks starting out with Mathematica. Let's try to understanding parsing.
Mathematica is actually very similar to Lisp in terms of code syntax. An expression like myFunc[a,b,c]
is equivalent to something like (myFunc a b c)
in Lisp. And just like Lisp, valid Mathematica code will already have the shape of an abstract syntax tree. This is a major contrast with languages like C.
Now, typical Mathematica code may not look like a tree, but that's because there is a ton of syntactic sugar available to use. The semi-colon is not a line-terminator, nor does it serve as an output suppressor--it's actually infix form for CompoundExpression
just like the plus sign, +
, is infix for Plus
. The suppression of output is just due to the fact that threre will be a Null
in the last spot of the CompoundExpression
, and raw Null
s don't get displayed by the front end.
Hold
and FullForm
are your friends here. FullForm
shows you what code is going to be executed by the back end after the syntactic sugar has been dealt with. Hold
keeps expressions from being evaluated. So, if you ever want to see what your code really says, you can wrap it with FullForm[Hold[...your code...]]
. So, let's look at
FullForm[Hold[
myFunction[] := (
a = b + c;
d = a - 1;
)]]
We get
Hold[SetDelayed[myFunction[], CompoundExpression[Set[a, Plus[b, c]], Set[d, Plus[a, -1]], Null]]]
What if we didn't have the parentheses?
FullForm[Hold[
myFunction[] :=
a = b + c;
d = a - 1;]]
Hold[CompoundExpression[SetDelayed[myFunction[], Set[a, Plus[b, c]]], Set[d, Plus[a, -1]], Null]]
So, the main issue here is NOT one of parentheses being required for function definitions, but instead one of simple precedence. Infix ;
has lower precedence than infix :=
. This is the only use for parentheses--they don't otherwise have any meaning. Also notice that newlines get removed. Newlines have no meaning either (although, aggravatingly, they can break Goto
as you discovered).
If that Null
looks weird, it's just because that's how the sugar of ;
is defined to work. A trailing ;
will get a Null
inserted after it. This is how we get the effect of suppressing output. The "result" of a CompoundExpression
is the result of its final term. so, something;
evaluates to Null
, which is a completely valid output value, but raw Null
just doesn't display in the front end.
One other "trick". The front end can help you find the tree structure. If you put your cursor somewhere in an expression and tap Control-.
(I'm using a Mac, but the command is called "Extend Selection" and you can find it in the Edit menu), the selection will expand to include the next "level" of the underlying syntax tree. So, for your myFunction
code, try the following with both forms (the one with parentheses and the one without): Select the "b" and repeatedly tap Control-.
.
That's a lot for now. Happy to answer other specific questions that come up as you play with this. As for where you can learn this stuff,