Online Book Reader

Home Category

Beautiful Code [268]

By Root 5032 0
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 thus:[§§]

[§§] In the first line of main, we could instead have written tid <-forkIO (hPutStr…), to bind the ThreadId returned by forkIO to tid. However, because we do not use the returned ThreadId, we are free to discard it by omitting the tid<-part.

main :: IO ( )

main = do { 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:

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:

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 that uses nTimes to print Hello 10 times:

main = nTimes 10 (hPutStr stdout "Hello\n")

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 my tutorial "Tackling the awkward squad."[||||]

[||||] Simon Peyton Jones, "Tackling the awkward squad: monadic input/output, concurrency, exceptions, and foreign-language calls in Haskell," C. A. R. Hoare, M. Broy, and R. Steinbrueggen, editors, Engineering theories of software construction, Marktoberdorf Summer School 2000, NATO ASI Series, pp. 47–96, IOS Press, 2001.

24.2.2. Transactions in Haskell

Now, we can return to our transfer function. Here is its code:

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 let's 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

Return Main Page Previous Page Next Page

®Online Book Reader