Software Transactional Memory is a promising new approach to the challenge of
concurrency, as I will explain in this section. I shall explain STM using Haskell,
the most beautiful programming language I know, because STM fits into Haskell
particularly elegantly. If you don’t know any Haskell, don’t worry; we’ll learn
it as we go.
## 3.1 Side effects and input/output in Haskell
Here is the beginning of the code for transfer in Haskell:
``` haskell
transfer :: Account -> Account -> Int -> IO ()
-- Transfer ’amount’ from account ’from’ to account ’to’
transfer from to amount = ...
```
The second line of this definition, starting “`--`”, is a comment. The first line
gives the _type signature_ for `transfer`. This signature says that `transfer` takes
as its arguments2 two values of type `Account` (the source and destination accounts), and an `Int` (the amount to transfer), and returns a value of type `IO ()`.
This result type says “`transfer` returns an action that, when performed, may
have some side effects, and then returns a value of type `()`”. The type `()`, pronounced “unit”, has just one value, which is also written `()`; it is akin to `void`
in C. So `transfer`’s result type `IO ()` announces that its side effects constitute
the only reason for calling it. Before we go further, we must explain how side
effects are handled in Haskell.
A “side effect” is anything that reads or writes mutable state. Input/output is
a prominent example of a side effect. For example, here are the signatures of
two Haskell functions with input/output effects:
``` haskell
hPutStr :: Handle -> String -> IO ()
hGetLine :: Handle -> IO String
```
We call any value of type `IO t` an “action”. So `(hPutStr h "hello")`3 is an
action that, when performed, will print `"hello"` on handle4 `h` and return the
unit value. Similarly, `(hGetLine h)` is an action that, when performed, will
read a line of input from handle `h` and return it as a `String`. We can glue
together little side-effecting programs to make bigger side-effecting programs
using Haskell’s “`do`” notation. For example, `hEchoLine` reads a string from the
input and prints it:
``` haskell
hEchoLine :: Handle -> IO String
hEchoLine h = do
s <- hGetLine h
hPutStr h ("I just read that " ++ s)
return s
```
@@@ Try it...
Here's a small program that calls the function `hEchoLine` and sets up data for it. Run it!
``` active haskell
{-# START_FILE main.hs #-}
import System.IO
hEchoLine :: Handle -> IO String
hEchoLine h = do
s <- hGetLine h
hPutStr h ("I just read that " ++ s)
return s
main = do
h <- openFile "test.txt" ReadWriteMode
str <- {-hi-}hEchoLine h{-/hi-}
hClose h
str1 <- readFile "test.txt"
hPutStr stdout str1
{-# START_FILE test.txt #-}
Haskell rules!
```
First, we `import` the appropriate library, in this case `System.IO`, which contains the definitions of `hGetLine`, `hPutStr`, and a few others used in `main`. Function `main` makes the call to `hEchoLine` with the appropriate argument -- a file handle, `h`.
We get the handle by calling `openFile` with two arguments: the name of the file and the file mode -- `ReadWriteMode` in this case. Finally, we read the whole modified file using `readFile` and send the result to the standard output, `stdout`, for display.
Notice that we are discarding the result of `hEchoLine`: `str`. If you want to display it, change the last line of `main`.
The file `test.txt` is provided too (feel free to edit its content and run the program again).
@@@
The notation:
``` haskell
do
a1
...
an
```
constructs an action by gluing together the
smaller actions _a1 . . . an_ in sequence. So `hEchoLine h` is an action that, when
performed, will first perform `hGetLine h` to read a line from `h`, naming the result `s`. Then it will perform `hPutStr` to print `s`, preceded5 by “`I just read: `”.
Finally, it returns the string `s`. This last line is interesting, because `return` is
not a built-in language construct: rather, it is a perfectly ordinary function with
type
``` haskell
return :: a -> IO a
```
The action `return v`, when performed, returns `v` without having caused any
side effects6. This function works on values of any type, and we indicate this
by using a type variable `a` in its type.
Input/output is one important sort of side effect. Another is the act of reading
or writing a mutable variable. For example, here is a function that increments
the value of a mutable variable:
``` haskell
incRef :: IORef Int -> IO ()
incRef var = do
val <- readIORef var
writeIORef var (val+1)
```
@@@ Try it...
Here is a small test program calling `incRef`:
``` active haskell
import System.IO
import Data.IORef
incRef :: IORef Int -> IO ()
incRef var = do
val <- readIORef var
writeIORef var (val+1)
main = do
var <- newIORef 42
{-hi-}incRef var{-/hi-}
val <- readIORef var
hPutStr stdout (show val)
```
This time `main` creates a new `IORef` with the initial value `42`, passes it to our function `incRef`, reads the new value from `IORef`, and displays it. To display a number we convert it to a string using the function `show`.
@@@
Here, `incRef var` is an action that first performs `readIORef var` to read the
value of the variable, naming its value `val`, and then performs `writeIORef`
to write the value `(val+1)` into the variable. The types of `readIORef` and
`writeIORef` are as follows:
``` haskell
readIORef :: IORef a -> IO a
writeIORef :: IORef a -> a -> IO ()
```
A value of type `IORef t` should be thought of as a pointer, or reference, to a
mutable location containing a value of type `t`, a bit like the type `(t *)` in C.
In the case of `incRef`, the argument has type `IORef Int` because `incRef` only
applies to locations that contain an `Int`.
So far I have explained how to build big actions by combining smaller ones
together — but how does an action ever actually get performed? In Haskell,
the whole program defines a single `IO` action, called `main`. To run the program
is to perform the action `main`. For example, here is a complete program:
``` active haskell
import System.IO
-- show
main :: IO ()
main = do
hPutStr stdout "Hello"
hPutStr stdout " world\n"
```
This program is a sequential program, because the `do`-notation combines `IO`
actions in sequence. To construct a concurrent program we need one more
primitive, `forkIO`:
``` haskell
forkIO :: IO a -> IO ThreadId
```
The function `forkIO`, which is built into Haskell, takes an `IO` action as its
argument, and spawns it as a concurrent Haskell thread. Once created, it is run
concurrently with all the other Haskell threads, by the Haskell runtime system.
For example, suppose we modified our main program thus7:
``` active haskell
import System.IO
import Control.Concurrent
-- show
main :: IO ()
main = do
forkIO (hPutStr stdout "Hello")
hPutStr stdout " world\n"
```
@@@ Note...
In the first line of main, we could instead have written `tid <- forkIO (hPutStr ...)`,
to bind the `ThreadId` returned by `forkIO` to `tid`. However, since we do not use the returned
`ThreadId`, we are free to discard it by omitting the “`tid <-`” part.
``` active haskell
import System.IO
import Control.Concurrent
main :: IO ()
main = do
tid <- forkIO (hPutStr stdout "Hello")
hPutStr stdout " world\n"
```
@@@
Now the two `hPutStr` actions would run concurrently. Which of them would
“win” (by printing its string first) is unspecified. Haskell threads spawned by
`forkIO` are extremely lightweight: they occupy a few hundred bytes of memory,
and it is perfectly reasonable for a single program to spawn thousands of them.
Gentle reader, you may by now be feeling that Haskell is a very clumsy and
verbose language. After all, our three-line definition of `incRef` accomplishes
no more than `x++` does in C! Indeed, in Haskell side effects are extremely explicit and somewhat verbose. However, remember first that Haskell is primarily
a _functional_ language. Most programs are written in the functional core of
Haskell, which is rich, expressive, and concise. Haskell thereby gently encourages you to write programs that make sparing use of side effects.
Second, notice that being explicit about side effects reveals a good deal of useful
information. Consider two functions:
``` haskell
f :: Int -> Int
g :: Int -> IO Int
```
From looking only at their types we can see that `f` is a pure function: it has
no side effects. Given a particular `Int`, say `42`, the call `(f 42)` will return the
same value every time it is called. In contrast, `g` has side effects, and this is
apparent in its type. Each time `g` is performed it may give a different result —
for example it may read from `stdin`, or modify a mutable variable — even if its
argument is the same every time. This ability to make side effects explicit will
prove very useful in what follows.
Lastly, actions are first-class values: they may be passed as arguments as well
as returned as results. For example, here is the definition of a (simplified) `for`
loop function, written entirely in Haskell rather than being built in:
``` haskell
nTimes :: Int -> IO () -> IO ()
nTimes 0 do_this = return ()
nTimes n do_this = do
do_this
nTimes (n-1) do_this
```
This recursive function takes an `Int` saying how many times to loop, and an action `do_this`; it returns an action that, when performed, performs the `do_this`
action `n` times. Here is an example of a use of `nTimes` to print “`Hello`” 10 times:
``` haskell
main = nTimes 10 (hPutStr stdout "Hello\n")
```
@@@ Try it...
``` active haskell
import System.IO
nTimes :: Int -> IO () -> IO ()
nTimes 0 do_this = return ()
nTimes n do_this = do
do_this
nTimes (n-1) do_this
main = nTimes 10 (hPutStr stdout "Hello\n")
```
We are calling `nTimes` with `10` and the action returned by `(hPutStr stdout "Hello\n")` that prints "Hello" to the standard input.
@@@
In effect, by treating actions as first-class values, Haskell supports _user-defined
control structures_.
This chapter is not the place for a full introduction to Haskell, or even to side
effects in Haskell. A good starting point for further reading is the tutorial
“_Tackling the awkward squad_” [9].
## 3.2 Transactions in Haskell
Now we can return to our `transfer` function. Here is its code:
``` haskell
transfer :: Account -> Account -> Int -> IO ()
-- Transfer ’amount’ from account ’from’ to account ’to’
transfer from to amount
= atomically (do deposit to amount
withdraw from amount)
```
The inner `do`-block should by now be fairly self-explanatory: we call `deposit`
to deposit amount in `to`, and `withdraw` to withdraw amount from account `from`.
We will write these auxiliary functions in a moment, but first look at the call
to `atomically`. It takes an action as its argument, and performs it atomically.
More precisely, it makes two guarantees:
> **Atomicity:** the effects of `atomically act` become visible to another thread
all at once. This ensures that no other thread can see a state in which
money has been deposited in to but not yet withdrawn from from.
> **Isolation:** during a call `atomically act`, the action `act` is completely unaffected by other threads. It is as if act takes a snapshot of the state of the
world when it begins running, and then executes against that snapshot.
Here is a simple execution model for `atomically`. Suppose there is a single,
global lock. Then `atomically act` grabs the lock, performs the action `act`,
and releases the lock. This implementation brutally ensures that no two atomic
blocks can be executed simultaneously, and thereby ensures atomicity.
There are two problems with this model. First, it does not ensure isolation
at all: while one thread is accessing an `IORef` inside an atomic block (holding
the Global Lock), there is nothing to stop _another_ thread writing the same
`IORef` directly (i.e. outside `atomically`, without holding the Global Lock),
thereby destroying the isolation guarantee. Second, performance is dreadful,
because every atomic block would be serialised even if no actual interference
was possible.
I will discuss the second problem shortly, in Section 3.3. Meanwhile, the first
objection is easily addressed with the type system. We give `atomically` the
following type:
``` haskell
atomically :: STM a -> IO a
```
The argument of atomically is an action of type `STM a`. An `STM` action is like
an `IO` action, in that it can have side effects, but the range of side effects for `STM`
actions is much smaller. The main thing you can do in an `STM` action is read
or write a transactional variable, of type `(TVar a)`, much as we could read or
write `IORefs` in an `IO` action8.
``` haskell
readTVar :: TVar a -> STM a
writeTVar :: TVar a -> a -> STM ()
```
`STM` actions can be composed together with the same `do`-notation as `IO` actions
— the `do`-notation is overloaded to work on both types, as is `return`9. Here,
for example, is the code for `withdraw`:
``` haskell
type Account = TVar Int
withdraw :: Account -> Int -> STM ()
withdraw acc amount = do
bal <- readTVar acc
writeTVar acc (bal - amount)
```
We represent an `Account` by a transactional variable containing an `Int` for the
account balance. Then withdraw is an `STM` action that decrements the balance
in the account by `amount`.
To complete the definition of `transfer` we can define `deposit` in terms of
`withdraw`:
``` haskell
deposit :: Account -> Int -> STM ()
deposit acc amount = withdraw acc (- amount)
```
@@@ Try it...
``` active haskell
import System.IO
import Control.Concurrent.STM
type Account = TVar Int
withdraw :: Account -> Int -> STM ()
withdraw acc amount = do
bal <- readTVar acc
writeTVar acc (bal - amount)
deposit :: Account -> Int -> STM ()
deposit acc amount = withdraw acc (- amount)
transfer :: Account -> Account -> Int -> IO ()
-- Transfer ’amount’ from account ’from’ to account ’to’
transfer from to amount
= atomically (do deposit to amount
withdraw from amount)
showAccount :: Account -> IO Int
showAccount acc = atomically (readTVar acc)
main = do
from <- atomically (newTVar 200)
to <- atomically (newTVar 100)
transfer from to 50
v1 <- showAccount from
v2 <- showAccount to
putStrLn $ (show v1) ++ ", " ++ (show v2)
```
We are uning `newTVar` to create two `TVar`s representing two accounts, `from` and `to`.
@@@
Notice that, `transfer` ultimately performs four primitive read/write actions: a
read and then write on account `to`, followed by a read and then write on account
`from`. These four actions execute atomically, and that meets the specification
given at the start of Section 2.
The type system neatly prevents us from reading or writing a `TVar` outside of a
transaction. For example, suppose we tried this:
``` haskell
bad :: Account -> IO ()
bad acc = do
hPutStr stdout "Withdrawing..."
withdraw acc 10
```
@@@ Try it...
This program won't compile:
``` active haskell
import System.IO
import Control.Concurrent.STM
type Account = TVar Int
withdraw :: Account -> Int -> STM ()
withdraw acc amount = do
bal <- readTVar acc
writeTVar acc (bal - amount)
bad :: Account -> IO ()
bad acc = do
hPutStr stdout "Withdrawing..."
withdraw acc 10
main = do
acc <- atomically (newTVar 200)
bad acc
hPutStr stdout "\nDone!\n"
```
@@@
This program is rejected because the `hPutStr` is an `IO` action, while the
withdraw is an `STM` action, and the two cannot be combined in a single do
block. If we wrap a call to `atomically` around the `withdraw`, all is well:
``` haskell
good :: Account -> IO ()
good acc = do
hPutStr stdout "Withdrawing..."
atomically (withdraw acc 10)
```
@@@ Try it...
This program compiles and runs:
``` active haskell
import System.IO
import Control.Concurrent.STM
type Account = TVar Int
withdraw :: Account -> Int -> STM ()
withdraw acc amount = do
bal <- readTVar acc
writeTVar acc (bal - amount)
good :: Account -> IO ()
good acc = do
hPutStr stdout "Withdrawing..."
{-hi-}atomically{-/hi-} (withdraw acc 10)
main = do
acc <- atomically (newTVar 200)
good acc
hPutStr stdout "\nDone!\n"
```
@@@
## 3.3 Implementing transactional memory
The guarantees of atomicity and isolation that I described earlier should be all
that a programmer needs in order to use STM. Even so, I often find it helpful
to have a reasonable implementation model to guide my intuitions, and I will
sketch one such implementation in this section. But remember that this is just
_one_ possible implementation. One of the beauties of the STM abstraction is
that it presents a small, clean interface that can be implemented in a variety of
ways, some simple and some sophisticated.
One particularly attractive implementation is well established in the database
world, namely _optimistic execution_. When `(atomically act)` is performed, a
thread-local _transaction log_ is allocated, initially empty. Then the action `act`
is performed, without taking any locks at all. While performing `act`, each call
to `writeTVar` writes the address of the `TVar` and its new value into the log; it
does not write to the `TVar` itself. Each call to `readTVar` first searches the log
(in case the `TVar` was written by an earlier call to `writeTVar`); if no such record
is found, the value is read from the `TVar` itself, and the `TVar` and value read
are recorded in the log. In the meantime, other threads might be running their
own atomic blocks, reading and writing `TVars` like crazy.
When the action `act` is finished, the implementation first _validates_ the log and,
if validation is successful, _commits_ the log. The validation step examines each
`readTVar` recorded in the log, and checks that the value in the log matches the
value currently in the real `TVar`. If so, validation succeeds, and the commit step
takes all the writes recorded in the log and writes them into the real `TVars`.
These steps are performed truly indivisibly: the implementation disables interrupts, or uses locks or compare-and-swap instructions — whatever is necessary
to ensure that validation and commit are perceived by other threads as completely indivisible. All of this is handled by the implementation, however, and
the programmer does not need to know or care how it is done.
What if validation fails? Then the transaction has had an inconsistent view of
memory. So we abort the transaction, re-initialise the log, and run `act` all over
again. This process is called _re-execution_. Since none of `act`’s writes have been
committed to memory, it is perfectly safe to run it again. However, notice that
it is crucial that act contains no effects _other than_ reads and writes on `TVars`.
For example, consider
``` haskell
atomically (do x <- readTVar xv
y <- readTVar yv
if x>y then launchMissiles
else return () )
```
where `launchMissiles :: IO ()` causes serious international side-effects.
Since the atomic block is executed without taking locks, it might have an inconsistent view of memory if other threads are concurrently modifying `xv` and
`yv`. If that happens, it would be a mistake to launch the missiles, and only _then_ discover that validation fails so the transaction should be re-run. Fortunately,
the type system prevents us running `IO` actions inside `STM` actions, so the above
fragment would be rejected by the type checker. This is another big advantage
of distinguishing the types of `IO` and `STM` actions.
@@@ Try it...
``` active haskell
import System.IO
import Control.Concurrent.STM
launchMissiles :: IO ()
launchMissiles = hPutStr stdout "Zzzing!"
main = do
xv <- atomically (newTVar 2)
yv <- atomically (newTVar 1)
atomically (do x <- readTVar xv
y <- readTVar yv
if x > y then launchMissiles
else return () )
```
@@@
## 3.4 Blocking and choice
Atomic blocks as we have introduced them so far are utterly inadequate to
coordinate concurrent programs. They lack two key facilities: _blocking_ and
_choice_. In this section I’ll describe how the basic STM interface is elaborated
to include them in a fully-modular way.
Suppose that a thread should _block_ if it attempts to overdraw an account (i.e.
withdraw more than the current balance). Situations like this are common in
concurrent programs: for example, a thread should block if it reads from an
empty buffer, or when it waits for an event. We achieve this in STM by adding
the single function `retry`, whose type is
``` haskell
retry :: STM a
```
Here is a modified version of withdraw that blocks if the balance would go
negative:
``` haskell
limitedWithdraw :: Account -> Int -> STM ()
limitedWithdraw acc amount = do
bal <- readTVar acc
if amount > 0 && amount > bal
then retry
else writeTVar acc (bal - amount)
```
@@@ Try it...
``` active haskell
import System.IO
import Control.Concurrent.STM
import Control.Concurrent
type Account = TVar Int
limitedWithdraw :: Account -> Int -> STM ()
limitedWithdraw acc amount = do
bal <- readTVar acc
if amount > 0 && amount > bal
then retry
else writeTVar acc (bal - amount)
delayDeposit acc amount = do
hPutStr stdout "Getting ready to deposit money...hunting through pockets...\n"
threadDelay 3000000
hPutStr stdout "OK! Depositing now!\n"
atomically ( do bal <- readTVar acc
writeTVar acc (bal + amount) )
main = do
acc <- atomically (newTVar 100)
forkIO (delayDeposit acc 1)
hPutStr stdout "Trying to withdraw money...\n"
atomically (limitedWithdraw acc 101)
hPutStr stdout "Successful withdrawal!\n"
```
We are forking a thread that calls `delayDeposit`, which waits for 3 seconds before depositing the amount. In the meanwhile `limitedWithraw` blocks because of insufficient funds. Soon after the deposit from the other thread goes through, `limitedWithdraw` succeeds.
@@@
The semantics of `retry` are simple: if a `retry` action is performed, the current
transaction is abandoned and retried at some later time. It would be correct to
`retry` the transaction immediately, but it would also be inefficient: the state of
the account will probably be unchanged, so the transaction will again hit the
`retry`. An efficient implementation would instead block the thread until some
other thread writes to `acc`. How does the implementation know to wait on `acc`?
Because the transaction read `acc` on the way to the `retry`, and that fact is
conveniently recorded in the transaction log.
The conditional in `limitedWithdraw` has a very common pattern: check that a
boolean condition is satisfied and, if not, `retry`. This pattern is easy to abstract
as a function, `check`:
``` haskell
check :: Bool -> STM ()
check True = return ()
check False = retry
```
Now we can use `check` to re-express `limitedWithdraw` a little more neatly:
``` haskell
limitedWithdraw :: Account -> Int -> STM ()
limitedWithdraw acc amount = do
bal <- readTVar acc
check (amount <= 0 || amount <= bal)
writeTVar acc (bal - amount)
```
@@@ Try it...
The same program using `check`, which is actually a library function:
``` active haskell
import System.IO
import Control.Concurrent.STM
import Control.Concurrent
type Account = TVar Int
limitedWithdraw :: Account -> Int -> STM ()
limitedWithdraw acc amount = do
bal <- readTVar acc
check (amount <= 0 || amount <= bal)
writeTVar acc (bal - amount)
delayDeposit acc amount = do
threadDelay 3000000
hPutStr stdout "Depositing right now!\n"
atomically ( do bal <- readTVar acc
writeTVar acc (bal + amount) )
main = do
acc <- atomically (newTVar 100)
forkIO (delayDeposit acc 1)
hPutStr stdout "Withdrawing... Hope the deposit has cleared...\n"
atomically (limitedWithdraw acc 101)
hPutStr stdout "Oh, phew!\n"
```
@@@
We now turn our attention to _choice_. Suppose you want to withdraw money
from account A if it has enough money, but if not then withdraw it from account
B? For that, we need the ability to choose an alternative action if the first one
retries. To support choice, STM Haskell has one further primitive action, called
`orElse`, whose type is
``` haskell
orElse :: STM a -> STM a -> STM a
```
Like `atomically` itself, `orElse` takes actions as its arguments, and glues them
together to make a bigger action. Its semantics are as follows. The action
`(orElse a1 a2)` first performs `a1`; if `a1` retries (i.e. calls `retry`), it tries `a2`
instead; if `a2` also retries, the whole action retries. It may be easier to see how
`orElse` is used:
``` haskell
limitedWithdraw2 :: Account -> Account -> Int -> STM ()
-- (limitedWithdraw2 acc1 acc2 amt) withdraws amt from acc1,
-- if acc1 has enough money, otherwise from acc2.
-- If neither has enough, it retries.
limitedWithdraw2 acc1 acc2 amt
= orElse (limitedWithdraw acc1 amt) (limitedWithdraw acc2 amt)
```
@@@ Try it...
``` active haskell
import System.IO
import Control.Concurrent.STM
import Control.Concurrent
type Account = TVar Int
limitedWithdraw :: Account -> Int -> STM ()
limitedWithdraw acc amount = do
bal <- readTVar acc
check (amount <= 0 || amount <= bal)
writeTVar acc (bal - amount)
showAcc name acc = do
bal <- atomically (readTVar acc)
hPutStr stdout (name ++ ": $")
hPutStr stdout (show bal ++ "\n")
limitedWithdraw2 :: Account -> Account -> Int -> STM ()
-- (limitedWithdraw2 acc1 acc2 amt) withdraws amt from acc1,
-- if acc1 has enough money, otherwise from acc2.
-- If neither has enough, it retries.
limitedWithdraw2 acc1 acc2 amt
= orElse (limitedWithdraw acc1 amt) (limitedWithdraw acc2 amt)
delayDeposit name acc amount = do
threadDelay 3000000
hPutStr stdout ("Depositing $" ++ show amount ++ " into " ++ name ++ "\n")
atomically ( do bal <- readTVar acc
writeTVar acc (bal + amount) )
main = do
acc1 <- atomically (newTVar 100)
acc2 <- atomically (newTVar 100)
showAcc "Left pocket" acc1
showAcc "Right pocket" acc2
forkIO (delayDeposit "Right pocket" acc2 1)
hPutStr stdout "Withdrawing $101 from either pocket...\n"
atomically (limitedWithdraw2 acc1 acc2 101)
hPutStr stdout "Successful withdrawal!\n"
showAcc "Left pocket" acc1
showAcc "Right pocket" acc2
```
We use a helper function `showAcc` to display the contents of accounts before and after the withdrawal. We have two accounts, `acc1` and `acc2`, both with insufficient funds for the `limitedWithdraw2` to succeed immediately. However, when the background thread deposits $1 into `acc2`, the call succeeds.
@@@
Since the result of `orElse` is itself an `STM` action, you can feed it to another call
to `orElse` and so choose among an arbitrary number of alternatives.
## 3.5 Summary so far
In this section I have introduced all the key transactional memory operations
supported by STM Haskell. They are summarised in Figure 1.

This figure
includes one operation that has not so far arisen: `newTVar` is the way in which
you can create new `TVar` cells, and we will use it in the following section.
» [Next: The Santa Claus problem](4-the-santa-claus-problem).
---
2 You may think it odd that there are three function arrows in this type signature, rather
than one. That’s because Haskell supports _currying_, which you can find described in any
book about Haskell (e.g. [13]), or on [Wikipedia](http://en.wikipedia.org/wiki/Currying). For the purposes of this paper, simply treat
all the types except the final one as arguments.
3 In Haskell we write function application using simple juxtaposition. In most languages you
would write `hPutStr(h,"hello")`, but in Haskell you write simply `(hPutStr h "hello")`.
4 A `Handle` in Haskell plays the role of a file descriptor in C: it says which file or pipe to
read or write. As in Unix, there are three pre-defined handles, `stdin`, `stdout`, and `stderr`.
5 The `(++)` operator concatenates two strings.
6 The `IO` type indicates the _possibility_ of side effects, not the certainty!
7 In the first line of `main`, we could instead have written `tid <- forkIO (hPutStr ...)`,
to bind the `ThreadId` returned by `forkIO` to `tid`. However, since we do not use the returned
`ThreadId`, we are free to discard it by omitting the “`tid <-`” part.
8 The nomenclature is inconsistent here: it would be more consistent to use either `TVar` and
`IOVar`, or `TRef` and `IORef`. But it would be disruptive to change at this stage; for better or
worse we have `TVar` and `IORef`.
9 This overloading of `do`-notation and `return` is not an ad-hoc trick to support `IO` and
`STM`. Rather, `IO` and `STM` are both examples of a common pattern, called a _monad_ [15], and
the overloading is achieved by expressing that common pattern using Haskell’s very general
_type-class_ mechanism [16, 10].
---
[9] Simon Peyton Jones. Tackling the awkward squad: monadic input/output,
concurrency, exceptions, and foreign-language calls in Haskell. In CAR
Hoare, M Broy, and R Steinbrueggen, editors, _Engineering Theories of
Software Construction, Marktoberdorf Summer School 2000_, NATO ASI
Series, pages 47–96. IOS Press, 2001.
[10] Simon Peyton Jones, Mark Jones, and Erik Meijer. Type classes: an exploration of the design space. In J Launchbury, editor, _Haskell workshop_,
Amsterdam, 1997.
[13] SJ Thompson. _Haskell: the craft of functional programming._ Addison
Wesley, 1999.
[15] PL Wadler. The essence of functional programming. In _20th ACM Sym-
posium on Principles of Programming Languages (POPL’92)_, pages 1–14.
ACM, Albuquerque, January 1992.
[16] PL Wadler and S Blott. How to make ad-hoc polymorphism less ad hoc.
In _Proc 16th ACM Symposium on Principles of Programming Languages,
Austin, Texas_. ACM, January 1989.