Beautiful Code [276]
24.3.5. Compiling and Running the Program
I have presented all the code for this example. If you simply add the appropriate import statements at the top, listed here, you should be good to go:[||||||||]
[||||||||] You can get the code online at http://research.microsoft.com/~simonpj/papers/stm/Santa.hs.gz.
module Main where
import Control.Concurrent.STM
import Control.Concurrent
import System.Random
To compile the code, use the Glasgow Haskell Compiler, GHC:[####]
[####] GHC is available for free at http://haskell.org/ghc.
$ ghc Santa.hs -package stm -o santa
Finally, you can run the program:
$ ./santa
----------
Ho! Ho! Ho! let's deliver toys
Reindeer 8 delivering toys
Reindeer 7 delivering toys
Reindeer 6 delivering toys
Reindeer 5 delivering toys
Reindeer 4 delivering toys
Reindeer 3 delivering toys
Reindeer 2 delivering toys
Reindeer 1 delivering toys
Reindeer 9 delivering toys
----------
Ho! Ho! Ho! let's meet in my study
Elf 3 meeting in the study
Elf 2 meeting in the study
Elf 1 meeting in the study
...and so on...
Beautiful Concurrency > Reflections on Haskell
24.4. Reflections on Haskell
Haskell is, first and foremost, a functional language. Nevertheless, I think that it is also the world's most beautiful imperative language. Considered as an imperative language, Haskell's unusual features are that:
Actions (which have effects) are rigorously distinguished from pure values by the type system.
Actions are first-class values. They can be passed to functions, returned as results, formed into lists, and so on, all without causing any side effects.
Using actions as first-class values, the programmer can define application-specific control structures, rather than make do with the ones provided by the language designer. For example, nTimes is a simple for loop, and choose implements a sort of guarded command. We also saw other applications of actions as values. In the main program, we used Haskell's rich expression language (in this case, list comprehensions) to generate a list of actions, which we then performed in order, using sequence_. Earlier, when defining helper1, we improved modularity by abstracting out an action from a chunk of code. To illustrate these points, I have perhaps overused Haskell's abstraction power in the Santa code, which is a very small program. For large programs, though, it is hard to overstate the importance of actions as values.
On the other hand, I have underplayed other aspects of Haskell—higher-order functions, lazy evaluation, data types, polymorphism, type classes, and so on—because of the focus on concurrency. Not many Haskell programs are as imperative as this one! You can find a great deal of information about Haskell at http://haskell.org, including books, tutorials, Haskell compilers and interpreters, Haskell libraries, mailing lists, and much more besides.
Beautiful Concurrency > Conclusion
24.5. Conclusion
My main goal is to persuade you that you can write programs in a fundamentally more modular way using STM than you can with locks and condition variables. First, though, note that transactional memory allows us to completely avoid many of the standard problems that plague lock-based concurrent programs (as explained earlier in the section "Locks Are Bad"). None of these problems arises in STM Haskell. The type system prevents you from reading or writing a TVar outside an atomic block, and because there are no programmer-visible locks, the questions of which locks to take, and in which order, simply do not arise. Other benefits of STM, which I lack the space to describe here, include freedom from lost wakeups and the treatment of exceptions and error recovery.
However, as we also discussed in the section "Locks Are Bad," the