0%

Haskell in Depth unlocks a new level of skill with this challenging language. Going beyond the basics of syntax and structure, this book opens up critical topics like advanced types, concurrency, and data processing. You’ll discover key parts of the Haskell ecosystem and master core design patterns that will transform how you write software.

Table of Contents

  1. Haskell in Depth
  2. Copyright
  3. dedication
  4. brief contents
  5. contents
  6. front matter
    1. foreword
    2. preface
    3. Functional programming
    4. Type system
    5. Lazy evaluation
    6. Tooling around Haskell
    7. What can be done using Haskell: Libraries
    8. acknowledgments
    9. about this book
    10. Who should read this book
    11. How this book is organized: A roadmap
    12. About the code
    13. Getting the sources
    14. Using cabal
    15. Using stack
    16. liveBook discussion forum
    17. about the author
    18. about the cover illustration
  7. Part 1. Core Haskell
  8. 1 Functions and types
    1. 1.1 Solving problems in the GHCi REPL with functions
    2. 1.2 From GHCi and String to GHC and Text
    3. 1.3 Functional programs as sets of IO actions
    4. 1.4 Embracing pure functions
    5. 1.4.1 Separating I/O from pure functions
    6. 1.4.2 Computing the most frequent words by sorting them
    7. 1.4.3 Formatting reports
    8. 1.4.4 Rule them all with IO actions
    9. Summary
  9. 2 Type classes
    1. 2.1 Manipulating a radar antenna with type classes
    2. 2.1.1 The problem at hand
    3. 2.1.2 Rotating a radar antenna with Eq, Enum, and Bounded
    4. 2.1.3 Combining turns with Semigroup and Monoid
    5. 2.1.4 Printing and reading data with Show and Read
    6. 2.1.5 Testing functions with Ord and Random
    7. 2.2 Issues with numbers and text
    8. 2.2.1 Numeric types and type classes
    9. 2.2.2 Numeric conversions
    10. 2.2.3 Computing with fixed precision
    11. 2.2.4 More about Show and Read
    12. 2.2.5 Converting recursive types to strings
    13. 2.3 Abstracting computations with type classes
    14. 2.3.1 An idea of a computational context and a common behavior
    15. 2.3.2 Exploring different contexts in parallel
    16. 2.3.3 The do notation
    17. 2.3.4 Folding and traversing
    18. Summary
  10. 3 Developing an application: Stock quotes
    1. 3.1 Setting the scene
    2. 3.1.1 Inputs
    3. 3.1.2 Outputs
    4. 3.1.3 Project structure
    5. 3.2 Exploring design space
    6. 3.2.1 Designing the user interface
    7. 3.2.2 Dealing with input data
    8. 3.2.3 Formatting reports
    9. 3.2.4 Plotting charts
    10. 3.2.5 Project dependencies overview
    11. 3.3 Implementation details
    12. 3.3.1 Describing data
    13. 3.3.2 Plotting charts
    14. 3.3.3 Preparing reports
    15. 3.3.4 Implementing the user interface
    16. 3.3.5 Connecting parts
    17. Summary
  11. Part 2. Introduction to application design
  12. 4 Haskell development with modules, packages, and projects
    1. 4.1 Organizing Haskell code with modules
    2. 4.1.1 Module structure, imports and exports, and module hierarchy
    3. 4.1.2 Custom Preludes
    4. 4.1.3 Example: containers-mini
    5. 4.2 Understanding Haskell packages
    6. 4.2.1 Packages at the GHC level
    7. 4.2.2 Cabal packages and Hackage
    8. 4.3 Tools for project development
    9. 4.3.1 Dependency management
    10. 4.3.2 Haskell projects as a collection of packages
    11. 4.3.3 Common project management activities and tools
    12. Summary
  13. 5 Monads as practical functionality providers
    1. 5.1 Basic monads in use: Maybe, Reader, Writer
    2. 5.1.1 Maybe monad as a line saver
    3. 5.1.2 Carrying configuration all over the program with Reader
    4. 5.1.3 Writing logs via Writer
    5. 5.2 Maintaining state via the State monad
    6. 5.2.1 Basic examples with the State monad
    7. 5.2.2 Parsing arithmetic expressions with State
    8. 5.2.3 RWS monad to rule them all: The game of dice
    9. 5.3 Other approaches to mutability
    10. 5.3.1 Mutable references in the IO monad
    11. 5.3.2 Mutable references in the ST monad
    12. Summary
  14. 6 Structuring programs with monad transformers
    1. 6.1 The problem of combining monads
    2. 6.1.1 Evaluating expressions in reverse Polish notation
    3. 6.1.2 Introducing monad transformers and monad stacks
    4. 6.2 IO-based monad transformer stacks
    5. 6.2.1 Describing a monad stack
    6. 6.2.2 Exploiting monad stack functionality
    7. 6.2.3 Running an application
    8. 6.2.4 Can we do it without RWST?
    9. 6.3 What is a monad transformer?
    10. 6.3.1 Step 0: Defining a type for a transformer
    11. 6.3.2 Step 1: Turning a monad stack into a monad
    12. 6.3.3 Step 2: Implementing the full monad stack functionality
    13. 6.3.4 Step 3: Supplying additional functionality
    14. 6.3.5 Using a transformer
    15. 6.4 Monad transformers in the Haskell libraries
    16. 6.4.1 Identity is where it all starts
    17. 6.4.2 An overview of the most common monad transformers
    18. Summary
  15. Part 3. Quality assurance
  16. 7 Error handling and logging
    1. 7.1 Overview of error-handling mechanisms in Haskell
    2. 7.1.1 The idea of exceptions
    3. 7.1.2 To use or not to use?
    4. 7.1.3 Programmable exceptions vs. GHC runtime exceptions
    5. 7.2 Programmable exceptions in monad stacks
    6. 7.2.1 The ExceptT monad transformer
    7. 7.2.2 Example: Evaluating RPN expressions
    8. 7.3 GHC runtime exceptions
    9. 7.3.1 An idea of extensible exceptions
    10. 7.3.2 Throwing exceptions
    11. 7.3.3 Catching exceptions
    12. 7.4 Example: Accessing web APIs and GHC exceptions
    13. 7.4.1 Application components
    14. 7.4.2 Exception-handling strategies
    15. 7.5 Logging
    16. 7.5.1 An overview of the monad-logger library
    17. 7.5.2 Introducing logging with monad-logger into the suntimes project
    18. Summary
  17. 8 Writing tests
    1. 8.1 Setting a scene: IPv4 filtering application
    2. 8.1.1 Development process overview
    3. 8.1.2 Initial implementation
    4. 8.2 Testing the IPv4 filtering application
    5. 8.2.1 Overview of approaches to testing
    6. 8.2.2 Testing Cabal projects with tasty
    7. 8.2.3 Specifications writing and checking with Hspec
    8. 8.2.4 Property-based testing with Hedgehog
    9. 8.2.5 Golden tests with tasty-golden
    10. 8.3 Other approaches to testing
    11. 8.3.1 Testing functions à la the REPL with doctest
    12. 8.3.2 Lightweight verification with LiquidHaskell
    13. 8.3.3 Code quality with hlint
    14. Summary
  18. 9 Haskell data and code at run time
    1. 9.1 A mental model for Haskell memory usage at run time
    2. 9.1.1 General memory structure and closures
    3. 9.1.2 Primitive unboxed data types
    4. 9.1.3 Representing data and code in memory with closures
    5. 9.1.4 A detour: Lifted types and the concept of strictness
    6. 9.2 Control over evaluation and memory usage
    7. 9.2.1 Controlling strictness and laziness
    8. 9.2.2 Defining data types with unboxed values
    9. 9.3 Exploring compiler optimizations by example
    10. 9.3.1 Optimizing code manually
    11. 9.3.2 Looking at GHC Core
    12. Summary
  19. 10 Benchmarking and profiling
    1. 10.1 Benchmarking functions with criterion
    2. 10.1.1 Benchmarking implementations of a simple function
    3. 10.1.2 Benchmarking an IPv4 filtering application
    4. 10.2 Profiling execution time and memory usage
    5. 10.2.1 Simulating iplookup usage in the real world
    6. 10.2.2 Analyzing execution time and memory allocation
    7. 10.2.3 Analyzing memory usage
    8. 10.3 Tuning performance of the IPv4 filtering application
    9. 10.3.1 Choosing the right data structure
    10. 10.3.2 Squeezing parseIP performance
    11. Summary
  20. Part 4. Advanced Haskell
  21. 11 Type system advances
    1. 11.1 Haskell types 101
    2. 11.1.1 Terms, types, and kinds
    3. 11.1.2 Delivering information with types
    4. 11.1.3 Type operators
    5. 11.2 Data kinds and type-level literals
    6. 11.2.1 Promoting types to kinds and values to types
    7. 11.2.2 Type-level literals
    8. 11.3 Computations over types with type families
    9. 11.3.1 Open and closed type synonym families
    10. 11.3.2 Example: Avoid character escaping in GHCi
    11. 11.3.3 Data families
    12. 11.3.4 Associated families
    13. 11.4 Generalized algebraic data types
    14. 11.4.1 Example: Representing dynamically typed values with GADTs
    15. 11.4.2 Example: Representing arithmetic expressions with GADTs
    16. 11.5 Arbitrary-rank polymorphism
    17. 11.5.1 The meaning
    18. 11.5.2 Use cases
    19. 11.6 Advice on dealing with type errors
    20. 11.6.1 Be explicit about types
    21. 11.6.2 Ask the compiler
    22. 11.6.3 Saying more about errors
    23. Summary
  22. 12 Metaprogramming in Haskell
    1. 12.1 Deriving instances
    2. 12.1.1 Basic deriving strategies
    3. 12.1.2 The problem of type safety and generalized newtype deriving
    4. 12.1.3 Deriving by an example with DerivingVia
    5. 12.2 Data-type-generic programming
    6. 12.2.1 Generic data-type representation
    7. 12.2.2 Example: Generating SQL queries
    8. 12.3 Template Haskell and quasiquotes
    9. 12.3.1 A tutorial on Template Haskell
    10. 12.3.2 Example: Generating remote function calls
    11. Summary
  23. 13 More about types
    1. 13.1 Types for specifying a web API
    2. 13.1.1 Implementing a web API from scratch
    3. 13.1.2 Implementing a web service with servant
    4. 13.2 Toward dependent types with singletons
    5. 13.2.1 Safety in Haskell programs
    6. 13.2.2 Example: Unsafe interface for elevators
    7. 13.2.3 Dependent types and substituting them with singletons
    8. 13.2.4 Example: Safe interface for elevators
    9. Summary
  24. Part 5. Haskell toolkit
  25. 14 Data-processing pipelines
    1. 14.1 Streaming data
    2. 14.1.1 General components and naive implementation
    3. 14.1.2 The streaming package
    4. 14.2 Approaching an implementation of pipeline stages
    5. 14.2.1 Reading and writing data efficiently
    6. 14.2.2 Parsing data with parser combinators
    7. 14.2.3 Accessing data with lenses
    8. 14.3 Example: Processing COVID-19 data
    9. 14.3.1 The task
    10. 14.3.2 Processing data
    11. 14.3.3 Organizing the pipeline
    12. Summary
  26. 15 Working with relational databases
    1. 15.1 Setting up an example
    2. 15.1.1 Sample database
    3. 15.1.2 Sample queries
    4. 15.1.3 Data representation in Haskell
    5. 15.2 Haskell database connectivity
    6. 15.2.1 Connecting to a database
    7. 15.2.2 Relating Haskell data types to database types
    8. 15.2.3 Constructing and executing SELECT queries
    9. 15.2.4 Manipulating data in a database
    10. 15.2.5 Solving tasks by issuing many queries
    11. 15.3 The postgresql-simple library
    12. 15.3.1 Connecting to a database
    13. 15.3.2 Relating Haskell data types to database types
    14. 15.3.3 Executing queries
    15. 15.4 The hasql ecosystem
    16. 15.4.1 Structuring programs with hasql
    17. 15.4.2 Constructing type-safe SQL statements
    18. 15.4.3 Implementing database sessions
    19. 15.4.4 Running database sessions
    20. 15.4.5 The need for low-level operations and decoding data manually
    21. 15.5 Generating SQL with opaleye
    22. 15.5.1 Structuring programs with opaleye
    23. 15.5.2 Describing database tables and their fields
    24. 15.5.3 Writing queries
    25. 15.5.4 Running queries
    26. Summary
  27. 16 Concurrency
    1. 16.1 Running computations concurrently
    2. 16.1.1 An implementation of concurrency in GHC
    3. 16.1.2 Low-level concurrency with threads
    4. 16.1.3 High-level concurrency with the async package
    5. 16.2 Synchronization and communication
    6. 16.2.1 Synchronized mutable variables and channels
    7. 16.2.2 Software transactional memory (STM)
    8. Summary
  28. appendix Further reading
    1. Books
    2. Research papers
  29. index
18.189.170.17