I'm guessing you're coming from a programming language where every expression must evaluate to a value, and if it didn't evaluate to something (like
5[Cos+Sin]), it's a syntax error. To me, Mathematica started to make a lot more sense, once I stopped thinking about functions and values, and started to think of every expression as evaluating to an "expression tree". (Note to long-time Mathematica users: I'm trying to explain this form the point of view of someone coming from a different programming language. I'm glossing over a lot of details like
Hold, but the "conceptual model" I'm trying to explain here was very useful for me when I started with MMA.)
a+b*c yields an expression tree. You can use
TreeForm[a + b*c] to display the actual tree:
The same is true for
a[b*c], or even
(b*c)[a]. Think of these things as tree data structures, not as expressions as you might know them from C or Perl. For instance, you can access parts of that data structure using normal array-index syntax:
(a + b*c) [[2, 1]] yields
b. There are a few basic rules how operators can be combined, so e.g.
x=[b] are invalid, but other than that, you can build any tree you want.
The next step is that you can tell Mathematica tree manipulation rules that it should automatically apply to these trees. You could for example write:
a[x_ + c] := "Hello"
Now, any time Mathematica evaluates a tree that matches the pattern
a[x_ + c], it will replace it with "Hello". Don't think of this as a function declaration. Think of it as a replacement rule. And you can define almost any kind of pattern matching and replacement rule. For example, you could write the replacement rules:
(x_ + b)[y_] := x*y
z_ + c := 5 z
and Mathematica would from then on happily evaluate an expression like
(5+b) to 30 or
5+c to 25.
(Note: Don't actually do this. It's a bad idea. In fact, it's such a bad idea that the people at Wolfram decided to protect the symbol
Plus from being overwritten, to prevent you from doing this. But if you
Unprotect[Plus], you could actually do this.)
Also note, that when you define a "variable":
z := 10;
you're using exactly the same machinery. (Again, ignoring details like
DownValues you can think of those as ugly performance improvement tricks.) This tells Mathematica to replace any expression tree that matches the pattern
z by 10. We're calling some of these patterns "functions", other "variables", but to the Mathematica kernel, there's really no difference.
(You're maybe asking yourself now: Wait, I declare variables using
:=, right? In the cases above, you can actually use both, with the same results.
:= are shorthands for
SetDelayed, respectively, which "register" a new pattern replacement rule with the Mathematica kernel. The only difference is that
Set evaluates the second argument, while
SetDelayed leaves it unevaluated.)
Here's another example, let's say you write:
x = f
This tells the Mathematica kernel that any expression that looks like
x is to be replaced with
f. So if you enter
x+y now, it evaluates to the expression tree
y+f. Mathematica doesn't care that
f looks like a function to you and me - to Mathematica, this is just another old tree structure.
Now let's you set:
f[a_] := a*2
Again, this registers a new replacement rule. Now if we evaluate
x+y, it (at first) evaluates to
y+f. But the kernel immediately notices that there's a replacement rule that matches
f, and replaces it, with
2*5. So the expression evaluates to
You should not think of this as "variable
x changed its value".
x never changed its value, it's still set to the expression tree
f. You can
Clear[f] and evaluate
x again to check.
All this is a bit confusing when you're coming from a "conventional" programming language. But it is extremely useful for manipulating symbolic expressions. For example, with the knowledge you have now, you could probably write a function that takes the derivative of a basic arithmetic expression in about 10 lines. Try that in a conventional programming language!