Mutable Data in the Real World
IO actions give us a way to represent computations that interact with the real-world. One of the important ways that we can interact with the real world that we haven’t yet looked at is how to read and write real-world state. In this chapter you’ll learn how to deal with persistent mutable values in the real world using IO references.
In this chapter you’ll learn how to build programs that interact with real-world data that can change over time as your program runs. You’ll also learn more about how Haskell programs run.
After you’ve finished this chapter you’ll know how to write functions that have persistent data that you can update over time.
Mutable data can be useful for building metrics and logging systems, writing certain efficient algorithms, and for debugging and testing your code. These things will all be important as you start building larger and more sophisticated programs.
traverseDirectoryIO
Write a new function, traverseDirectoryIO
that has the type:
traverseDirectoryIO :: FilePath -> (FilePath -> IO a) -> IO [a]
This function should behave like traverseDirectory'
but should accept a
function returning an IO action, rather than a value.
Hint 1
Some high level hint text
Hint 2
Some more detailed hint text
Hint 3
Even more detailed hint text
Solution
A complete solution for the exercise
Timing Pure Functions
The timeFunction
that you built as you worked through this chapter only
supports timing IO actions. Try writing a version of this function that also
works for pure values, with the type:
timePureFunction :: Metrics -> String -> a -> IO a
What are the limitations to your implementation function? Are there things that a user of the function could do to ensure that the timing information was better?
Hint 1
Some high level hint text
Hint 2
Some more detailed hint text
Hint 3
Even more detailed hint text
Solution
A complete solution for the exercise
Metrics Strictness
Consider the MetricsStore
type that you defined earlier in this chapter:
data MetricsStore = MetricsStore
successCount :: Int
{ failureCount :: Int
, callDuration :: Map.Map String Int
,deriving (Eq, Show) }
How might you make use of strictness to improve the performance of metrics? Try writing some metrics collecting functions using several different approaches to strictness and profiling the results.
Hint 1
Some high level hint text
Hint 2
Some more detailed hint text
Hint 3
Even more detailed hint text
Solution
A complete solution for the exercise