Real World Haskell

  • Introduction: Why Haskell?
    • Have we got a deal for you!
      • Novelty
      • Power
      • Enjoyment
    • What to expect from this book
      • A little bit about you
    • What to expect from Haskell
      • Compared to traditional static languages
      • Compared to dynamic languages
      • Haskell in industry and open source
      • Compilation, debugging, and performance analysis
      • Bundled and third party libraries
    • A brief sketch of Haskell’s history
      • Prehistory
      • Early antiquity
      • The modern era
    • Helpful resources
      • Reference material
      • Applications and libraries
      • The Haskell community
    • Acknowledgments
      • Bryan
      • John
      • Don
      • Revival
      • Thank you to our reviewers
  • Chapter 1: Getting Started
    • Your Haskell environment
    • Getting started with ghci, the interpreter
    • Basic interaction: using ghci as a calculator
      • Simple arithmetic
      • An arithmetic quirk: writing negative numbers
      • Boolean logic, operators, and value comparisons
      • Operator precedence and associativity
      • Undefined values, and introducing variables
      • Dealing with precedence and associativity rules
    • Command line editing in ghci
    • Lists
      • Operators on lists
    • Strings and characters
    • First steps with types
    • A simple program
    • Exercises
  • Chapter 2: Types and Functions
    • Why care about types?
    • Haskell’s type system
      • Strong types
      • Static types
      • Type inference
    • What to expect from the type system
    • Some common basic types
    • Function application
    • Useful composite data types: lists and tuples
      • Exercises
    • Functions over lists and tuples
      • Passing an expression to a function
    • Function types and purity
    • Haskell source files, and writing simple functions
      • Just what is a variable, anyway?
      • Conditional evaluation
    • Understanding evaluation by example
      • Lazy evaluation
      • A more involved example
      • Recursion
      • Ending the recursion
      • Returning from the recursion
      • What have we learned?
    • Polymorphism in Haskell
      • Reasoning about polymorphic functions
    • The type of a function of more than one argument
    • Exercises
    • Why the fuss over purity?
    • Conclusion
  • Chapter 3: Defining Types, Streamlining Functions
    • Defining a new data type
      • Naming types and values
    • Type synonyms
    • Algebraic data types
      • Tuples, algebraic data types, and when to use each
      • Analogues to algebraic data types in other languages
    • Pattern matching
      • Construction and deconstruction
      • Further adventures
      • Variable naming in patterns
      • The wild card pattern
      • Exhaustive patterns and wild cards
    • Record syntax
    • Parameterised types
    • Recursive types
      • Exercises
    • Reporting errors
      • A more controlled approach
    • Introducing local variables
      • Shadowing
      • The where clause
      • Local functions, global variables
    • The offside rule and white space in an expression
      • A note about tabs versus spaces
      • The offside rule is not mandatory
    • The case expression
    • Common beginner mistakes with patterns
      • Incorrectly matching against a variable
      • Incorrectly trying to compare for equality
    • Conditional evaluation with guards
    • Exercises
  • Chapter 4: Functional Programming
    • Thinking in Haskell
    • A simple command line framework
    • Warming up: portably splitting lines of text
      • A line ending conversion program
    • Infix functions
    • Working with lists
      • Basic list manipulation
      • Safely and sanely working with crashy functions
      • Partial and total functions
      • More simple list manipulations
      • Working with sublists
      • Searching lists
      • Working with several lists at once
      • Special string-handling functions
      • Exercises
    • How to think about loops
      • Explicit recursion
      • Transforming every piece of input
      • Mapping over a list
      • Selecting pieces of input
      • Computing one answer over a collection
      • The left fold
      • Why use folds, maps, and filters?
      • Folding from the right
      • Left folds, laziness, and space leaks
      • Exercises
      • Further reading
    • Anonymous (lambda) functions
    • Partial function application and currying
      • Sections
    • As-patterns
    • Code reuse through composition
      • Use your head wisely
    • Tips for writing readable code
    • Space leaks and strict evaluation
      • Avoiding space leaks with seq
      • Learning to use seq
  • Chapter 5: Writing a library: working with JSON data
    • A whirlwind tour of JSON
    • Representing JSON data in Haskell
    • The anatomy of a Haskell module
    • Compiling Haskell source
    • Generating a Haskell program, and importing modules
    • Printing JSON data
    • Type inference is a double-edged sword
    • A more general look at rendering
    • Developing Haskell code without going nuts
    • Pretty printing a string
    • Arrays and objects, and the module header
    • Writing a module header
    • Fleshing out the pretty printing library
      • Compact rendering
      • True pretty printing
      • Following the pretty printer
      • Exercises
    • Creating a package
      • Writing a package description
      • GHC’s package manager
      • Setting up, building, and installing
    • Practical pointers and further reading
  • Chapter 6: Using Type Classes
    • The need for type classes
    • What are type classes?
    • Declaring type class instances
    • Important Built-In Type Classes
      • Show
      • Read
      • Serialization with Read and Show
      • Numeric Types
      • Equality, Ordering, and Comparisons
    • Automatic Derivation
    • Type classes at work: making JSON easier to use
      • More helpful errors
      • Making an instance with a type synonym
    • Flexible instances
    • Living in an open world
      • When do overlapping instances cause problems?
      • How does show work for strings?
    • How to give a type a new identity
      • Differences between data and newtype declarations
      • Summary: the three ways of naming types
    • JSON type classes without overlapping instances
      • Exercises
    • The dreaded monomorphism restriction
    • Conclusion
  • Chapter 7: I/O
    • Classic I/O in Haskell
      • Pure vs. I/O
      • Why Purity Matters
    • Working With Files and Handles
      • More on openFile
      • Closing Handles
      • Seek and Tell
      • Standard Input, Output, and Error
      • Deleting and Renaming Files
      • Temporary Files
    • Extended Example: Functional I/O and Temporary Files
    • Lazy I/O
      • hGetContents
      • readFile and writeFile
      • A Word On Lazy Output
      • interact
        • Filters with interact
    • The IO Monad
      • Actions
      • Sequencing
      • The True Nature of Return
    • Is Haskell Really Imperative?
    • Side Effects with Lazy I/O
    • Buffering
      • Buffering Modes
      • Flushing The Buffer
    • Reading Command-Line Arguments
    • Environment Variables
  • Chapter 8: Efficient File Processing, Regular Expressions, and File Name Matching
    • Efficient file processing
      • Binary I/O and qualified imports
      • Text I/O
    • File name matching
    • Regular expressions in Haskell
      • TODO: Explain how to install regex-posix with Cabal or Stack
      • The many types of result
    • More about regular expressions
      • Mixing and matching string types
      • Other things you should know
    • Translating a glob pattern into a regular expression
      • TODO Explain -XFlexibleContexts
      • Exercises
    • An important aside: writing lazy functions
    • Making use of our pattern matcher
      • Exercises
    • Handling errors through API design
      • Exercises
    • Putting our code to work
    • Exercises
  • Chapter 9: I/O case study: a library for searching the filesystem
    • The find command
    • Starting simple: recursively listing a directory
      • Revisiting anonymous and named functions
      • Why provide both mapM and forM?
    • A naive finding function
    • Predicates: from poverty to riches, while remaining pure
    • Sizing a file safely
      • The acquire-use-release cycle
        • Exercises
    • A domain specific language for predicates
      • Avoiding boilerplate with lifting
      • Gluing predicates together
      • Defining and using new operators
    • Controlling traversal
      • Exercises
    • Density, readability, and the learning process
    • Another way of looking at traversal
      • Exercises
    • Useful coding guidelines
      • Common layout styles
    • Exercises
  • Chapter 10: Code case study: parsing a binary data format
    • Greyscale files
    • Parsing a raw PGM file
    • Getting rid of boilerplate code
    • Implicit state
      • The identity parser
      • Record syntax, updates, and pattern matching
      • A more interesting parser
      • Obtaining and modifying the parse state
      • Reporting parse errors
      • Chaining parsers together
    • Introducing functors
      • Constraints on type definitions are bad
      • Infix use of fmap
      • Thinking more about functors
    • Writing a functor instance for Parse
    • Using functors for parsing
    • Rewriting our PGM parser
    • Future directions
    • Exercises
  • Chapter 11: Testing and Quality Assurance
    • QuickCheck: type-based testing
      • Testing for properties
      • Testing against a model
    • Testing case study: specifying a pretty printer
      • Generating test data
      • Testing document construction
      • Using lists as a model
      • Putting it altogether
    • Measuring test coverage with HPC
  • Chapter 12: Barcode Recognition
    • A little bit about barcodes
      • EAN-13 encoding
    • Introducing arrays
      • Arrays and laziness
      • Folding over arrays
      • Modifying array elements
      • Exercises
    • Encoding an EAN-13 barcode
    • Constraints on our decoder
    • Divide and conquer
    • Turning a colour image into something tractable
      • Parsing a colour image
      • Greyscale conversion
      • Greyscale to binary, and type safety
    • What have we done to our image?
    • Finding matching digits
      • Run length encoding
      • Scaling run lengths, and finding approximate matches
      • List comprehensions
      • Remembering a match’s parity
        • Another kind of laziness, of the keyboarding variety
      • Chunking a list
      • Generating a list of candidate digits
    • Life without arrays or hash tables
      • A forest of solutions
      • A brief introduction to maps
        • Type constraints
        • Partial application awkwardness
        • Getting started with the API
      • Further reading
    • Turning digit soup into an answer
      • Solving for check digits in parallel
      • Completing the solution map with the first digit
      • Finding the correct sequence
    • Working with row data
    • Pulling it all together
    • A few comments on development style
  • Chapter 13. Data Structures
    • Association Lists
    • Maps
    • Functions Are Data, Too
    • Extended Example: /etc/passwd
    • Extended example: Numeric Types
      • First Steps
      • Completed Code
      • Exercises
    • Taking advantage of functions as data
      • Turning difference lists into a proper library
      • Lists, difference lists, and monoids
    • General purpose sequences
  • Chapter 14. Monads
    • Introduction
    • Revisiting earlier code examples
      • Maybe chaining
      • Implicit state
    • Looking for shared patterns
    • The Monad type class
    • And now, a jargon moment
    • Using a new monad: show your work!
      • Information hiding
      • Controlled escape
      • Leaving a trace
      • Using the Logger monad
    • Mixing pure and monadic code
    • Putting a few misconceptions to rest
    • Building the Logger monad
      • Sequential logging, not sequential evaluation
      • The writer monad
    • The Maybe monad
      • Executing the Maybe monad
      • Maybe at work
    • The list monad
      • Understanding the list monad
      • Putting the list monad to work
    • Desugaring of do blocks
      • Monads as a programmable semicolon
      • Why go sugar-free?
    • The state monad
      • Almost a state monad
      • Reading and modifying the state
      • Will the real state monad please stand up?
      • Using the State monad: generating random values
      • A first attempt at purity
      • Random values in the State monad
        • Exercises
      • Running the state monad
      • What about a bit more state?
    • Another way of looking at monads
    • The monad laws, and good coding style
  • Chapter 15. Programming with monads
    • Golfing practice: association lists
    • Generalised lifting
    • Looking for alternatives
      • The name mplus does not imply addition
      • Rules for working with MonadPlus
      • Failing safely with MonadPlus
    • Adventures in hiding the plumbing
      • Supplying random numbers
      • Another round of golf
    • Separating interface from implementation
      • Multi-parameter type classes
      • Functional dependencies
      • Rounding out our module
      • Programming to a monad’s interface
    • The reader monad
    • A return to automated deriving
    • Hiding the IO monad
      • Using a newtype
      • Designing for unexpected uses
      • Using type classes
      • Isolation and testing
      • The writer monad and lists
      • Arbitrary I/O revisited
      • Exercises
  • Chapter 16. Using Parsec
    • First Steps with Parsec: Simple CSV Parsing
    • The sepBy and endBy Combinators
    • Choices and Errors
      • Lookahead
      • Error Handling
    • Extended Example: Full CSV Parser
    • Parsec and Alternative
    • Parsing an URL-encoded query string
    • Supplanting regular expressions for casual parsing
    • Parsing without variables
    • Applicative functors for parsing
    • Applicative parsing by example
    • Parsing JSON data
    • Parsing a HTTP request
      • Backtracking and its discontents
      • Parsing headers
      • Exercises
  • Chapter 17. Interfacing with C: the FFI
    • Foreign language bindings: the basics
      • Be careful of side effects
      • A high level wrapper
    • Regular expressions for Haskell: a binding for PCRE
      • Simple tasks: using the C preprocessor
      • Binding Haskell to C with hsc2hs
      • Adding type safety to PCRE
      • Binding to constants
      • Automating the binding
    • Passing string data between Haskell and C
      • Memory management: let the garbage collector do the work
      • A high level interface: marshalling data
      • Mashalling ByteStrings
      • Allocating local C data: the Storable class
      • Putting it all together
    • Matching on strings
      • Extracting information about the pattern
      • Pattern matching with substrings
      • The real deal: compiling and matching regular expressions
  • Chapter 18. Monad transformers
    • Motivation: boilerplate avoidance
    • A simple monad transformer example
    • Common patterns in monads and monad transformers
    • Stacking multiple monad transformers
      • Hiding our work
      • Exercises
    • Moving down the stack
      • When explicit lifting is necessary
    • Understanding monad transformers by building one
      • Creating a monad transformer
      • More type class instances
      • Replacing the Parse type with a monad stack
      • Exercises
    • Transformer stacking order is important
    • Putting monads and monad transformers into perspective
      • Interference with pure code
      • Overdetermined ordering
      • Runtime overhead
      • Unwieldy interfaces
      • Pulling it all together
  • Chapter 19. Error handling
    • Error Handling with Data Types
      • Use of Maybe
        • Loss and Preservation of Laziness
        • Usage of the Maybe Monad
      • Use of Either
        • Custom Data Types for Errors
        • Monadic Use of Either
    • Exceptions
      • First Steps with Exceptions
      • Laziness and Exception Handling
      • Using handle
      • Selective Handling of Exceptions
      • I/O Exceptions
      • Throwing Exceptions
      • Dynamic Exceptions
    • Exercises
    • Error handling in monads
      • A tiny parsing framework
      • Exercises
  • Chapter 20. Systems Programming in Haskell
    • Running External Programs
    • Directory and File Information
    • Program Termination
    • Dates and Times
      • ClockTime and CalendarTime
      • File Modification Times
    • Extended Example: Piping
      • Using Pipes for Redirection
      • Better Piping
      • Final Words on Pipes
  • Chapter 21. Using Databases
    • Overview of HDBC
    • Installing HDBC and Drivers
    • Connecting to Databases
    • Transactions
    • Simple Queries
    • SqlValues
    • Query Parameters
    • Prepared Statements
    • Reading Results
      • Reading with Statements
      • Lazy Reading
    • Database Metadata
    • Error Handling
  • Chapter 22. Extended Example: Web Client Programming
    • Basic Types
    • The Database
    • The Parser
    • Downloading
    • Main Program
  • Chapter 23. GUI Programming with gtk2hs
    • Installing gtk2hs
    • Overview of the GTK+ Stack
    • User Interface Design with Glade
      • Glade Concepts
    • Event-Driven Programming
    • Initializing the GUI
    • The Add Podcast Window
    • Long-Running Tasks
    • Using Cabal
    • Exercises
  • Chapter 24. Concurrent and multicore programming
    • Defining concurrency and parallelism
    • Concurrent programming with threads
      • Threads are nondeterministic
      • Hiding latency
    • Simple communication between threads
    • The main thread and waiting for other threads
      • Safely modifying an MVar
      • Safe resource management: a good idea, and easy besides
      • Finding the status of a thread
      • Writing tighter code
    • Communicating over channels
    • Useful things to know about
      • MVar and Chan are non-strict
      • Chan is unbounded
    • Shared-state concurrency is still hard
      • Deadlock
      • Starvation
      • Is there any hope?
    • Exercises
    • Using multiple cores with GHC
      • Runtime options
      • Finding the number of available cores from Haskell
      • Choosing the right runtime
    • Parallel programming in Haskell
      • Normal form and head normal form
      • Sequential sorting
      • Transforming our code into parallel code
      • Knowing what to evaluate in parallel
      • What promises does par make?
      • Running our code, and measuring performance
      • Tuning for performance
      • Exercises
    • Parallel strategies and MapReduce
      • Separating algorithm from evaluation
      • Separating algorithm from strategy
      • Writing a simple MapReduce definition
      • MapReduce and strategies
      • Sizing work appropriately
      • Efficiently finding line-aligned chunks
      • Counting lines
      • Finding the most popular URLs
      • Conclusions
  • Chapter 25. Profiling and optimization
    • Profiling Haskell programs
      • Collecting runtime statistics
      • Time profiling
      • Space profiling
    • Controlling evaluation
      • Strictness and tail recursion
      • Adding strictness
    • Understanding Core
    • Advanced techniques: fusion
      • Tuning the generated assembly
      • Conclusions
  • Chapter 26. Advanced library design: building a Bloom filter
    • Introducing the Bloom filter
    • Use cases and package layout
    • Basic design
      • Unboxing, lifting, and bottom
    • The ST monad
    • Designing an API for qualified import
    • Creating a mutable Bloom filter
    • The immutable API
    • Creating a friendly interface
      • Re-exporting names for convenience
      • Hashing values
      • Turning two hashes into many
      • Implementing the easy creation function
    • Creating a Cabal package
      • Dealing with different build setups
      • Compilation options, and interfacing to C
    • Testing with QuickCheck
      • Polymorphic testing
      • Writing Arbitrary instances for ByteStrings
      • Are suggested sizes correct?
    • Performance analysis and tuning
      • Profile-driven performance tuning
    • Exercises
  • Chapter 27. Sockets and Syslog
    • Basic Networking
    • Communicating with UDP
      • UDP Client Example: syslog
      • UDP Syslog Server
    • Communicating with TCP
      • Handling Multiple TCP Streams
      • TCP Syslog Server
      • TCP Syslog Client
  • Chapter 28. Software transactional memory
    • The basics
    • Some simple examples
    • STM and safety
    • Retrying a transaction
      • What happens when we retry?
    • Choosing between alternatives
      • Using higher order code with transactions
    • I/O and STM
    • Communication between threads
    • A concurrent web link checker
      • Checking a link
      • Worker threads
      • Finding links
      • Command line parsing
      • Pattern guards
    • Practical aspects of STM
      • Getting comfortable with giving up control
      • Using invariants
  • Appendix. Characters, strings, and escaping rules
    • Writing character and string literals
    • International language support
    • Escaping text
      • Single-character escape codes
      • Multiline string literals
      • ASCII control codes
      • Control-with-character escapes
      • Numeric escapes
      • The zero-width escape sequence
  • Bibliography