Number theory contains numerous basic calculations that can benefit from parallelism. For example, consider the calculation of the factorial of a number and the associative property of multiplication. If the factorial of n is:

Figure 1. Simple Flowchart for the Code: You can see the interactions among the main functions in the code here.

That is, you can divide the whole interval of numbers in t+1 smaller intervals, calculate the partial products, and then multiply them again to obtain the final result.

With a multiprocessor machine, I wondered if by calculating a, b, ..., k simultaneously and then multiplying the results together I could shorten the total elapsed time. In an attempt to solve this problem, I wrote a small piece of Erlang code. While not a usable implementation of the factorial function, the code does serve to explore Erlang syntax and its potential for concurrency computation (see Figure 1).

The remainder of this article shows you how you can use Erlang's message-passing method to enable parallel processes to work together concurrently. During the analysis of the code, I explain some syntax features and show you how recursion, pattern matching, and concurrency work in Erlang. Covering all Erlang syntax and features is beyond the scope of this article, but you can find a lot of documentation on the Internet.

Anatomy of an Erlang Program

Erlang programs start with declarations that contain the dash character (-) in position 0 and that make assertions about the naming, availability, and definitions of functions. Take a look at a couple of declarations:

-module(fact).

Modules

Erlang uses modules. The module fact resides in a file named fact.erl, and it requires the module declaration at the top (click here to download the file). As you likely noticed, all statements have to be terminated with a dot:

-export([start/2]).

In each module, you can write a lot of functions, but only the ones exported can be seen and called outside the module itself. The notation start/2 means that the exported function named start accepts two arguments:

This is the way you define a function. Again, notice that the whole definition is a statement and that the single instructions that compose it have to be separated by a comma.

Variables

Variables start with a capital letter. To avoid hidden effects, you can bind them to a constant value only once. A variable can be bound or not but the compiler will issue a warning if you use an unbound variable!

Erlang provides a few types of variables. The most used are numbers, atoms, lists, and tuples. Atoms are constant values with names that start with small letters. Otherwise, you have to enclose them in quotation marks. Lists and tuples respectively store a variable number and a fixed number of numbers, atoms, lists, and tuples. You enclose lists in brackets and tuples in curly brackets. Erlang is a dynamically typed language, so it performs variable type checking at run time.

The following line is the Erlang syntax to call a function that is exported by a module. In this case, the function seq of the module lists returns a list containing all integers from 1 to Number. The basic installation of Erlang provides a set of utility modules such as lists:

compute(ProcNum, lists:seq(1,Number)),

Note the call to the function compute. Here is the definition of that function:

compute(_, Numbers) when length(Numbers) == 1 ->
...
compute(ProcNum, Numbers) when ProcNum == 1 ->
...
compute(ProcNum, Numbers) ->
...

You can define a function in more than one way. In this case, the three variants of the function differ by the presence of what is called a guard clause. But, as you will see further in the code, the same function can also have different definitions based on the number and the kind of input parameters.