Haskell High Performance Programming Table of Contents
Total Page:16
File Type:pdf, Size:1020Kb
Haskell High Performance Programming Table of Contents Haskell High Performance Programming Credits About the Author About the Reviewer www.PacktPub.com eBooks, discount offers, and more Why subscribe? Preface What this book covers What you need for this book Who this book is for Conventions Reader feedback Customer support Downloading the example code Downloading the color images of this book Errata Piracy Questions 1. Identifying Bottlenecks Meeting lazy evaluation Writing sum correctly Weak head normal form Folding correctly Memoization and CAFs Constant applicative form Recursion and accumulators The worker/wrapper idiom Guarded recursion Accumulator parameters Inspecting time and space usage Increasing sharing and minimizing allocation Compiler code optimizations Inlining and stream fusion Polymorphism performance Partial functions Summary 2. Choosing the Correct Data Structures Annotating strictness and unpacking datatype fields Unbox with UNPACK Using anonymous tuples Performance of GADTs and branching Handling numerical data Handling binary and textual data Representing bit arrays Handling bytes and blobs of bytes Working with characters and strings Using the text library Builders for iterative construction Builders for strings Handling sequential data Using difference lists Difference list performance Difference list with the Writer monad Using zippers Accessing both ends fast with Seq Handling tabular data Using the vector package Handling sparse data Using the containers package Using the unordered-containers package Ephemeral data structures Mutable references are slow Using mutable arrays Using mutable vectors Bubble sort with vectors Working with monads and monad stacks The list monad and its transformer Free monads Working with monad transformers Speedup via continuation-passing style Summary 3. Profile and Benchmark to Your Heart's Content Profiling time and allocations Setting cost centres manually Setting cost centres automatically Installing libraries with profiling Debugging unexpected crashes with profiler Heap profiling Cost centre-based heap profiling Objects outside the heap Retainer profiling Biographical profiling Benchmarking using the criterion library Profile and monitor in real time Monitoring over HTTP with ekg Summary 4. The Devil's in the Detail The anatomy of a Haskell project Useful fields and flags in cabal files Test suites and benchmarks Using the stack tool Multi-package projects Erroring and handling exceptions Handling synchronous errors The exception hierarchy Handling asynchronous errors Throw and catch in other monads besides IO Writing tests for Haskell Property checks Unit testing with HUnit Test frameworks Trivia at term-level Coding in GHC PrimOps Control inlining Using rewrite rules Specializing definitions Phase control Trivia at type-level Phantom types Functional dependencies Type families and associated types Useful GHC extensions Monomorphism Restriction Extensions for patterns and guards Strict-by-default Haskell Summary 5. Parallelize for Performance Primitive parallelism and the Runtime System Spark away Subtle evaluation – pseq When in doubt, use the force The Eval monad and strategies Composing strategies Fine-tune granularity with chunking and buffering The Par monad and schedules spawn for futures and promises Non-deterministic parallelism with ParIO Diagnosing parallelism – ThreadScope Data parallel programming – Repa Playing with Repa in GHCi Mapping and delayed arrays Reduction via folding Manifest representations Delayed representation and fusion Indices, slicing, and extending arrays Convolution with stencils Cursored and partitioned arrays Writing fast Repa code Additional libraries Example from image processing Loading the image from file Identifying letters with convolution Extracting strings from an image Testing and evaluating performance Summary 6. I/O and Streaming Reading, writing, and handling resources Traps of lazy I/O File handles, buffering, and encoding Binary I/O Textual I/O I/O performance with filesystem objects Sockets and networking Acting as a TCP/IP client Acting as a TCP server (Unix domain sockets) Raw UDP traffic Networking above the transport layer Managing resources with ResourceT Streaming with side-effects Choosing a streaming library Simple streaming using io-streams Creating input streams Using combinators and output streams Handling exceptions and resources in streams An example of parsing using io-streams and attoparsec Streaming using pipes Composing and executing pipes For loops and category theory in pipes Handling exceptions in pipes Strengths and weaknesses of pipes Streaming using conduits Handling resources and exceptions in conduits Resuming conduits Logging in Haskell Logging with FastLogger More abstract loggers Timed log messages Monadic logging Customizing monadic loggers Summary 7. Concurrency and Performance Threads and concurrency primitives Threads and mutable references Avoid accumulating thunks Atomic operations with IORefs MVar MVars are fair MVar as a building block Broadcasting with Chan Software Transactional Memory STM example – Bank accounts Alternative transactions Exceptions in STM Runtime System and threads Masking asynchronous exceptions Asynchronous processing Using the Async API Async example – Timeouts Composing with Concurrently Lifting up from I/O Top-level mutable references Lifting from a base monad Lifting base with exception handling Summary 8. Tweaking the Compiler and Runtime System (GHC) Using GHC like a pro Operating GHC Circular dependencies Adjusting optimizations and transformations The state hack Floating lets in and out Eliminating common subexpressions Liberate-case duplicates code Compiling via the LLVM route Linking and building shared libraries Preprocessing Haskell source code Enforcing type-safety using Safe Haskell Tuning GHC's Runtime System Scheduler and green threads Sparks and spark pool Bounded threads and affinity Indefinite blocking and weak references Heap, stack, and memory management Evaluation stack in Haskell Tuning the garbage collector Parallel GC Profiling and tracing options Tracing using eventlog Options for profiling and debugging Summary of useful GHC options Basic usage The LLVM backend Turn optimizations on and off Configuring the Runtime System (compile-time) Safe Haskell Summary of useful RTS options Scheduler flags Memory management Garbage collection Runtime System statistics Profiling and debugging Summary 9. GHC Internals and Code Generation Interpreting GHC's internal representations Reading GHC Core Spineless tagless G-machine Primitive GHC-specific features Kinds encode type representation Datatype generic programming Working example – A generic sum Generating Haskell with Haskell Splicing with $(…) Names in templates Smart template constructors The constN function Lifting Haskell code to Q with quotation brackets Launching missiles during compilation Reifying Haskell data into template objects Deriving setters with Template Haskell Quasi-quoting for DSLs Summary 10. Foreign Function Interface From Haskell to C and C to Haskell Common types in Haskell and C Importing static functions and addresses Exporting Haskell functions Compiling a shared library Function pointers and wrappers Haskell callbacks from C Data marshal and stable pointers Allocating memory outside the heap Pointing to objects in the heap Marshalling abstract datatypes Marshalling in standard libraries Summary 11. Programming for the GPU with Accelerate Writing Accelerate programs Kernels – The motivation behind explicit use and run Working with elements and scalars Rudimentary array computations Example – Matrix multiplication Flow control and conditional execution Inspecting generated code Running with the CUDA backend Debugging CUDA programs More Accelerate concepts Working with tuples Folding, reducing, and segmenting Accelerated stencils Permutations in Accelerate Using the backend foreign function interface Summary 12. Scaling to the Cloud with Cloud Haskell Processes and message-passing Creating a message type Creating a Process Spawning and closures Running with the SimpleLocalNet backend Using channels Establishing bidirectional channels Calling a remote process Handling failure Firing up monitors Matching on the message queue Linking processes together Message-passing performance Nodes and networking Summary 13. Functional Reactive Programming The tiny discrete-time Elerea Mutually recursive signals Signalling side-effects Dynamically changing signal networks Performance and limitations in Elerea Events and signal functions with Yampa Adding state to signal functions Working with time Switching and discrete-time events Integrating to the real world Reactive-banana – Safe and simple semantics Example – First GUI application Graphical display with wxWidgets Combining events and behaviors Switching events and behaviors Observing moments on demand Recursion and semantics Adding input and output Input via polling or handlers Reactimate output Input and output dynamically Summary 14. Library Recommendations Representing data Functional graphs Numeric data for special use Encoding and serialization Binary serialization of Haskell values Encoding to and from other formats CSV input and output Persistent storage, SQL, and NoSQL acid-state and safecopy persistent and esqueleto HDBC and add-ons Networking and HTTP HTTP clients and servers Supplementary HTTP libraries JSON remote procedure calls Using WebSockets Programming a REST API Cryptography Web technologies Parsing and