In order to start using CAL as a language, we have to touch on the very nature of CAL. Here are the points that you must keep in mind. To begin with, program text is called "code" and is made up of statements referred to as "functions". There is a set of brackets made up of the left and right parentheses characters that enclose every complete function statement which is usually composed of a function key word and one or more parameter key words, numbers or variable names, all referred to as "arguments". There may be bracketed statements within other bracketed statements, often referred to as "nested" functions. Here is an example. Suppose we wish to write a program for washing a car. In its simplest form you would say:
(wash the car clean)
This statement is a complete function and as such is enclosed by a pair of brackets. It has the function keyword "wash" which is the operation to be performed, and the two arguments "the car" and "clean" which are what the function is going to operate on. There needs to be more information than that in order to convey the full operation of washing a car. However, no matter how we brake this function up into smaller (nested) functions, the enclosing brackets must never be ignored. I have given each part of the function its own color to make it easier to follow the breakdown. Here is a first breakdown:
(wash the car (using soap and water))
We have introduced a second "nested" function into the original function. This second function was the argument "clean" but it has now been expanded into function of its own. The key word "wash" still has two arguments, but one of them is now the nested "using" function with its arguments all enclosed in its own set of brackets. The "wash" function sees the new nested "using" function as a chunk of data to be operated on just like it sees "the car". As far as "wash" is concerned, there is no difference between having data like "the car" or a nested function like "using" as arguments. The system that brakes these words down and does the actual work merely resolves the "using" function into the result "clean" first and then substitutes this result for the function "using" when it starts to resolve the "wash" function. However, this still isn't enough detail for a computer to wash a car, so going a step further:
(wash (assemble the side panels and hood and roof and bumpers) (using (mix detergent and perfume) and (combine hydrogen and oxygen)))
When the computer executes this program, the deepest nested functions are resolved first and their results are inserted as substitutions for those functions in order to resolve the next layer of functions whose results are substituted for those functions in the next layer and so on. In this case, before the computer can resolve "wash" into a final result of "a clean car", it must resolve all of the nested functions starting with the inner most functions. First it resolves "mix" with its arguments "detergent" and "perfume". Once it performs the operation "mix" on these two arguments, the result is "soap". Now "soap" is substituted for the "mix" function in the "using" function. Next the computer performs the "combine" function on the arguments "hydrogen" and "oxygen" to obtain the result "water" which is now substituted into the "using" function as well. All nested functions now resolved, the computer performs "using" on the substituted arguments "soap" and "water" to end up with "clean" which is then substituted into the "wash" function in place of the nested function "using". Now the computer must resolve the other argument in "wash" by performing the operation "assemble" on the arguments "side panels", "hood", "roof" and "bumpers" at which point it reached the result "the car". Now "the car" is substituted into the "wash" function and the operation "wash" is performed using "the car" and "clean" to reach the final result of "a clean car". Programs must be built out of these small building blocks in order for there to be flexibility. If in the above example there was no brake down for "the car" and "the car" was the smallest unit the computer could use, then we would not be able to wash a truck or motorcycle because "the car" is the only keyword the computer understands. In the above example, however, we could have "assemble" operate on the arguments that represent the components of a truck or motorcycle or boat or whatever, thus allowing us to wash lots of things, not just a car. In the same way, if "water" was the only keyword the computer understood, we could use nothing else for washing. In this example, "combine" could be used to generate steam or a solvent for washing an engine and "mix" could make more than just soap such as mixing window washing solution. If all we ever wanted the computer to do was just wash a car using soap and water, we wouldn't need a program at all. We would just build a computer that does nothing but use soap and water to wash cars and save ourselves the aggravation!
Getting back to the above example of nested functions, can you see how the brackets are grouped? Each function is enclosed by brackets and when some of them fit together to build another function, those brackets are added to the brackets of the greater function. Lets look at another more mathematical example. Here is a formula for the result of 6 starting with the most complex formula and resolving backwards to a simpler form. Again I use color to make the process easier to follow.
(2 + (3 - 1) + ((8 / 2) - 2))
Which results in:
(2 + (2) + ((4) - 2))
(2 + 2 + (4 - 2))
(2 + 2 + 2)
When writing in CAL and most languages that use brackets in this way, the code tends to be arranged with one function on a line and the closing brackets of complex functions (functions made up of other functions) on their own lines. Indenting is also used to keep the code readable. To demonstrate this form, lets look at a logical program using filler words to represent functions. This example will introduce a few CAL operators such as "do" "if" and the very important "forEachEvent". Note that the spelling and capitalization of these and future key words is critical and cannot be taken for granted. For example, CAL understands forEachEvent but would have no idea what to do with ForEachEvent or foreachevent or for Each Event. I'll explain what these key words mean and what they tell CAL to do later. For now, just look at the form and observe the colors of the brackets.
(do (declare a variable) (declare another variable) (forEachEvent (do (something) (another something) (if (this) (then something) (otherwise something else) ) ) ) )
Confused? You bet! Here's how this worked. The key word "do" tells CAL that even though it would expect one function at this point, there will be several instead. The first "do" indicates that the program will have several functions one after another to be run one at a time. These will be the first variable declaration, the second declaration and the "forEachEvent" loop. What is a loop? Well, it's a type of function that repeats over and over until some condition is satisfied. In this case, the "forEachEvent" loop runs a pass for every event in the selected part of the sequence until it finishes the last event, then program execution continues with the function, if any, that follows it. The reason for the declaration statements is that we must make sure variables are declared before they are referenced in the code. In other words, if you are going to use a variable to hold the value of a note, say the highest note you wish some function to recognize, and you wish to call that variable "topend", then you must tell CAL to expect to see it in the code and to save room for it in memory under the label "topend". In this example, two variables are declared and then the loop is executed. There are only these 3 functions in the program. It just so happens that the last one, the loop, is further broken down into sub-functions like our car wash example above. The "forEachEvent" loop takes the events in the tracks you have highlighted starting at the "From" marker and ending at the "Thru" marker and performs the nested functions within its brackets on each event one at a time. The "do" after the "forEachEvent" statement lets CAL know that this loop is also made up of several functions. They are (something), the next (another something), and the "if" function. As it happens, the "if" function is of two minds. They go if (this) is true, execute function (then something). On the other hand, if (this) is false, execute function (otherwise something else) instead. After the "if" function has made up its mind and selected the appropriate result function for execution, the program loops back to the start of the "forEachEvent" loop and runs the whole thing again for the next event in the sequence. When the last event in the sequence is dealt with, the program stops. Notice the closing brackets at the end of the program which terminate the nested functions one at a time. You can see by the colors how they associate with the opening brackets. Now, if you could also write the program like this:
(do (declare a variable) (declare another variable) (forEachEvent (do (something)(another something) (if (this) (than something) (otherwise something else)))))
well, OK, but God help you if you would have to troubleshoot the code or if you have left out a bracket someplace. Making the code readable is half the job. With proper formatting, you can match the closing brackets with the opening ones by the indention. Keeping one function to a line also helps in maintaining a logical understanding of what the program is doing along its various points. Aside from making the code readable to humans, CAL couldn't care less if there is indention or if functions and closing brackets are on their own lines. The form is for our benefit. Let me qualify this just a bit. CAL does care if there is indention after the opening "do" statement, but only to the extent that the CAL interpreter seems to need this indention to confirm that there is valid CAL code being presented. Failing to indent can result in an error message. For a discussion of this and other formatting quirks, see the Hidden Traps In The CAL Editor section of the Tips, Techniques and Work-Arounds page. However, beyond this, CAL doesn't care what the code looks like, if the indention is even or if the code is readable just so long as it follows the rules of syntax.