Chapter 1. Getting Comfortable

Erlang has a tricky learning curve for many people. It starts gently for a little while, then gets much much steeper as you realize the discipline involved, and then goes nearly vertical for a little while as you try to figure out how that discipline affects getting work done—and then it’s suddenly calm and peaceful with a gentle grade for a long time as you reapply what you’ve learned in different contexts.

Before that climb, it’s best to get comfortable in the sunny meadows at the bottom of the learning curve. Erlang’s shell, its command-line interface, is a cozy place to get started and a good place to start figuring out what works and what doesn’t work in Erlang. Its features will spare you headaches later, so settle in!

Installation

Erlang is officially available from http://www.erlang.org/download.html. For this edition, I used Erlang/OTP 19, but any version of Erlang more recent than 17 should work. (Ericsson reliably releases a new version of Erlang every year or so.)

If you’re on Windows, it’s easy. Download the Windows binary file, run the installer, and you’re set. If you are a brave beginner tackling your first programming language, this approach is easily your best bet.

On Linux or macOS, you may be able to download the source file and compile it. If the compilation approach doesn’t work or isn’t for you, Erlang Solutions offers a number of installs at https://www.erlang-solutions.com/resources/download.html. Also, many different package managers (Debian, Ubuntu, MacPorts, Brew, and so on) include Erlang. It may not be the very latest version, but having Erlang running is much better than not having Erlang running.

Note

Erlang is increasingly part of the default installation on many systems, including Ubuntu Linux, largely thanks to the spread of CouchDB.

Firing It Up

On Mac OS X or Linux, go to the command line and type erl. On Windows, go to the command line and type werl.

You’ll see something like the following code sample, likely with a cursor next to the 1> prompt:

lang/OTP 19 [erts-8.2] [64-bit] [smp:8:8] [async-threads:10]

Eshell V8.2  (abort with ^G)

1>

You’re in Erlang!

First Steps: The Shell

Before moving on to the excitement of programming Erlang, it’s worth noting how to quit. The shell suggests ^G, Ctrl-G, which will bring you to a mysterious (for now) user switch command. (Ctrl-C will bring you to a menu.) The simplest way to quit, allowing everything that might be running in the shell to exit normally, is q().:

1> q().
ok
2> SimonMacBook:~ simonstl$

So what have you done here? You’ve issued a shell command, calling a function q that itself calls the init:stop() function built into Erlang. The period after the command tells Erlang you’re done with the line. It reports back with ok, prints a new line number (it always does that after a period), and drops you back out to the regular command line, in this case a bash shell on your laptop.

If you had left off the period after q(), the results would look a little different. You’d have started a new line but the command count wouldn’t update, so the line would still start with 1>. When this happens, you can just type . and press Enter to finish your command:

1> q()
1> .
ok
2> SimonMacBook:~ simonstl$

Including the period at the end of the line will soon become second nature, but leaving it off can create a lot of confusion at the start.

Warning

Quitting Erlang with q(). turns off everything Erlang is doing, period. That’s fine when you’re working locally, but will become a bad idea when you’re connecting to a remote shell. To quit the shell without the risk of shutting down the Erlang runtime on another system, try Ctrl-G and then entering q, followed by the Enter key.

Moving through Text

If you explore the shell, you’ll find that many things work the way they do in other shells. The left and right arrow keys move you backward and forward through the line you’re editing. Some of the key bindings echo the emacs text editor. Ctrl-A will take you to the beginning of a line, while Ctrl-E will take you back to the end of the line. If you get two characters in the wrong sequence, pressing Ctrl-T will transpose them.

Like most Unix shells, pressing the Tab key will make the shell try to autocomplete what you’ve written, though in this case it’s looking for module or function names (you’ll see them soon), not filenames.

Also, as you type closing parentheses or square brackets, the cursor will highlight the corresponding opening parenthesis or square bracket.

Moving through History

The up and down arrow keys run through the history, making it easy to reissue commands.

When you use the up and down arrows, the history will be broken down by newlines, not by periods, so if you left a period off in a prior command you’ll need to add it again. If you want to see what’s in the history, try h(). You can also specify how much history to keep around with history(N) and results(N). You can tell Erlang to execute a given line again with e(N), and reference a given result value with v(N). Those line numbers can be useful!

Moving through Files

The Erlang shell does understand filesystems to some extent because you may need to move through them to reach the files that will become part of your program. The commands have the same names as Unix commands but are expressed as functions.

The Erlang shell starts wherever you opened the shell, and you can figure out where that is with pwd():

4> pwd().
/Users/simonstl
ok
5>

To change directories, use the cd() command, but you’ll need to wrap the argument not only in parentheses but also in quotes, preferably double quotes:

5> cd(..).
* 1: syntax error before: '..'
5> cd("..").
/Users
ok
6> cd("simonstl").
/Users/simonstl
ok
7>

You can look around with the ls() command, which will list files in the current directory if you give it no arguments, and list files in a specified directory if you give it one argument.

Doing Something

One of the easiest ways to get started playing with Erlang is to use the shell as a calculator. You can enter mathematical expressions and get useful results:

Eshell V5.9  (abort with ^G)
1> 2+2.
4
2> 27-14.
13
3> 35*42023943.
1470838005
4> 200/15.
13.333333333333334
5> 200 div 15.
13
6> 200 rem 15.
5
7> 3*(4+15).
57

The first three operators are addition (+), subtraction (-), and multiplication (*), which work the same way whether you’re working with integer values or floating points. The fourth, /, supports division where you expect a floating point (a number with a decimal part) result. If you want an integer result (and have integer arguments), use the div operator instead, with rem to get the remainder, as shown on lines 5 and 6. Parentheses let you modify the order in which operators are processed, as shown on line 7. (The normal order of operations is listed in Appendix A.)

Erlang will accept integers in place of floats, but floats are not always welcome where integers are used. If you need to convert a floating-point number to an integer, you can use the round() built-in function:

8> round(200/15).
13

The round() function drops the decimal part of the number. If the decimal part is greater than or equal to .5, it increases the integer part by 1, rounding up. If you’d rather just drop the decimal part completely, use the trunc() function, which effectively always rounds down.

You can also refer to a previous result by its line number using v(). For example:

9> 4*v(8).
52

The result on line 8 was 13, and 4*13 is 52.

If you’re feeling adventurous, you can use negative numbers to reference prior results. v(-1) is the previous result, v(-2) is the result before that, and so on.

Calling Functions

If you want to do more powerful calculations, Erlang’s math module offers pretty much the classic set of functions supported by a scientific calculator. The functions return floating-point values. The constant pi is available as a function, math:pi(). Trigonometric, logarithmic, exponential, square root, and (except on Windows) even the Gauss error functions are readily available. (The trigonometric functions take their arguments in radians, not degrees, so be ready to convert if necessary.) Using these functions is a little verbose because of the need to prefix them with math:, but it’s still reasonably sane.

For example, to get the sine of zero radians, you’d write:

1> math:sin(0).
0.0

Note that it’s 0.0, not just 0, indicating that the number is a floating point.

To calculate the cosine of pi and 2pi radians, you’d write:

2> math:cos(math:pi()).
-1.0
3> math:cos(2*math:pi()).
1.0

To calculate 2 taken to the 16th power, you’d use:

4> math:pow(2,16).
65536.0

The full set of mathematical functions supported by Erlang’s math module is listed in Appendix A.

Numbers in Erlang

Erlang recognizes two kinds of numbers: integers and floating-point numbers (often called floats). It’s easy to think of integers as “whole numbers,” with no decimal part, and floats as “decimal numbers,” with a decimal point and some value (even if it’s 0) to the right of the decimal. 1 is an integer, 1.0 is a floating-point number.

However, it’s a little trickier than that. Erlang treats integers and floats very differently from each other. Erlang lets you store massive numbers as integers, but whether they’re big or small, they are always precise. You don’t need to worry about their values being off by just a little.

Floats, on the other hand, cover a wide range of numbers but with limited precision. Erlang uses the 64-bit IEEE 754-1985 “double-precision” representation. This means that it keeps track of about 15 decimal digits plus an exponent. It can also represent some large numbers—powers up to positive or negative 308 are available—but because it tracks only a limited number of digits, results will vary a little more than may seem convenient, especially when you want to do comparisons:

1> 3487598347598347598437583475893475843749245.0.
3.4875983475983474e42
2> 2343243.345435893850234543339545.
2343243.3454358936
3> 0.0000000000000000000000000000023432432432432234232324.
2.3432432432432235e-30

As you can see, some digits get left behind, and the overall magnitude of the number is represented with an exponent.

When you enter floating-point numbers, you must always also have at least one number to the left of the decimal point, even if it’s zero. Otherwise Erlang reports a syntax error—it doesn’t understand what you’re doing:

4> .0000000000000000000000000000023432432432432234232324.
* 1: syntax error before: 23432432432432234232324

You can also write floats using the digits plus exponent notation:

7> 2.923e127.
2.923e127
8> 7.6345435e-231.
7.6345435e-231

Floats’ lack of precision can cause anomalous results. For example, the sine of zero is zero, and the sine of pi is also zero. However, if you calculate this in Erlang, you won’t quite get to zero with the float approximation Erlang provides for pi:

1> math:sin(0).
0.0
2> math:sin(math:pi()).
1.2246467991473532e-16

If Erlang’s representation of pi went further, and its calculations went further, the result for line 2 would be closer to zero.

If you need to keep track of money, integers are going to be a better bet. Use the smallest available unit—cents for US dollars, for instance—and remember that those cents are 1/100 of a dollar. (Financial transactions can go to much smaller fractions, but you’ll still want to represent them as integers with a known multiplier.) For more complex calculations, though, you’ll want to use floats, and just be aware that the results will be imprecise.

If you need to do calculations on integers using a base other than 10, you can use Base#Value notation. For example, if you wanted to specify the binary value of 1010111, you could write:

3> 2#1010111.
87

Erlang reports back with the base 10 value of the number. Similarly, you can specify hexadecimal numbers by using 16 instead of 2:

4> 16#cafe.
51966

Erlang lets you use either upper- or lowercase for hexdecimal numbers: 16#CAFE and 16#CaFe also produce 51966. You aren’t limited to the traditional binary (base 2), octal (base 8), and hexadecimal (base 16) choices. If you want to work in base 18, or any base up to 36, you can:

5> 18#gaffe.
1743080
Note

Why might you use base 36? It’s an extremely easy way to create keys that look like a combination of letters and numbers, but resolve neatly to numbers. The 6-digit codes airlines use to identify tickets, like G6ZV1N, are easily treated as base 36. (However, they usually leave out some digits and letters that are easily confused, such as 0 and O, and 1 and l.)

To make any of these numbers negative just put a minus sign () in front of them. This works with normal integers, Base#Value notation, and floats:

6> -1234.
-1234
7> -16#cafe.
-51966
8> -2.045234324e6.
-2045234.324

Working with Variables in the Shell

The v() function lets you refer to the results of previous expressions, but it’s not exactly convenient to keep track of result numbers, and the v() function works only in the shell. It isn’t a general-purpose mechanism. A more reasonable solution stores values with textual names, creating variables.

Erlang variable names begin with a capital letter or an underscore. Normal variables start with a capital letter, whereas underscores start “don’t care” variables, variables you don’t actually intend to use. For now, stick with normal variables. You assign a value to a variable using a syntax that should be familiar from algebra or other programming languages, here N is used as the variable:

1> N=1.
1

To see the value of a variable, just type its name:

2> N.
1

To see Erlang protest at your rude behavior, try assigning the variable a new value:

3> N=2.
** exception error: no match of right-hand side value 2
4> N=N+1.
** exception error: no match of right-hand side value 2

What’s happening here? Erlang expects the right-hand side of an expression, after the =, to match the left-hand side. It’s willing to make that happen if a variable on the left side isn’t bound yet, as was the case with N=1 in the first line. However, once the variable N is set to 1, Erlang interprets N=2 as 1=2, which it won’t accept. N=N+1 also evaluates to 1=2, and doesn’t work. Erlang’s single assignment model, where each variable can be assigned a value only once in a given context, imposes discipline whose value you will see in later chapters.

Erlang expressions work like algebra, where N never equals N+1. It just can’t happen that way. However, once you’ve set N to 1, it’s fine to try expressions that also come to one:

5> N=2-1.
1
6> N=15 div (3*5).
1

This will get much more important when you start to take advantage of Erlang’s pattern-matching capabilities. You can also write the following:

7> 1=N.
1

Erlang won’t attempt to bind any variables when they appear on the right side of the equals sign, and this just effectively asks Erlang to compare 1 to 1. Try it with 2, however, and Erlang complains that there isn’t a match; 2 does not equal 1:

8> 2=N.
** exception error: no match of right-hand side value 1

You can also use bound variables in calculations, for example to create new bound variables. Here’s one called Number:

9> Number=N*4+N.
5
10> 6*Number.
30

When you assign a value to a variable, you should make sure that all the calculations are on the right side of the equals sign. Even though I know that M should be 6 when 2*M = 3*4, Erlang doesn’t:

11> 2*M=3*4.
* 1: illegal pattern

The shell will remember your variables until you quit or tell it to forget them. Code in Erlang functions doesn’t forget, until the functions stop running.

Seeing Your Bound Variables

After poking around the shell for a while using it as a calculator (try it!), you may find you’ve forgotten what variables you’ve already bound. If you need a reminder, the b() shell command can help:

11> b().
N = 1
Number = 5
ok

Clearing Bound Variables in the Shell

In the shell, and only in the shell, you can clear all variable bindings or you can clear specific variable bindings. This may prove useful after an egregious typo or to reset your console for new calculations, but it isn’t an option you’ll have in regular code.

To clear a specific variable, removing its binding and letting you set a new value, use the f() function, giving the variable name as an argument:

12> f(N).
ok
13> b().
Number = 5
ok
14> N=2.
2

To clear all the bound variables in the shell, just call f() with no arguments:

15> b().
N = 2
Number = 5
ok
16> f().
ok
17> b().
ok

They all disappeared.

Before moving on to the next chapter, which will introduce modules and functions, spend some time playing in the Erlang shell. The experience, even at this simple level, will help you move forward. Use variables, and see what happens with large integers. Erlang supports large numbers very well. Try mixing numbers with decimal values (floats) and integers in calculations, and see what happens. Nothing should be difficult yet, though I suspect the idea of variables that don’t change values gives you a hint of what’s to come.

Note

You can learn more about installation and working with the shell in Chapter 2 of Erlang Programming (O’Reilly); Chapters 2 and 3 of Programming Erlang 2nd Edition (Pragmatic); Section 2.1 of Erlang and OTP in Action (Manning); and Chapter 1 of Learn You Some Erlang For Great Good! (No Starch Press).

Get Introducing Erlang, 2nd Edition now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.