Table of contents : Praise for the First Edition Functional Programming in Scala, Second Edition Copyright contents front matter foreword to the first edition foreword to the second edition preface to the second edition acknowledgments about this book How this book is structured Audience How to read this book Code conventions and downloads Setting expectations liveBook discussion forum about the authors Part 1. Introduction to functional programming 1 What is functional programming? 1.1 Understanding the benefits of functional programming 1.1.1 A program with side effects 1.1.2 A functional solution: Removing the side effects 1.2 Exactly what is a (pure) function? 1.3 Referential transparency, purity, and the substitution model 1.4 Conclusion Summary 2 Getting started with functional programming in Scala 2.1 Introducing Scala the language 2.1.1 Running our program 2.2 Objects and namespaces 2.3 Higher-order functions: Passing functions to functions 2.3.1 A short detour: Writing loops functionally 2.3.2 Writing our first higher-order function 2.4 Polymorphic functions: Abstracting over types 2.4.1 An example of a polymorphic function 2.4.2 Calling higher-order functions with anonymous functions 2.5 Following types to implementations 2.6 Conclusion Summary 2.7 Exercise answers 3 Functional data structures 3.1 Defining functional data structures 3.2 Pattern matching 3.3 Data sharing in functional data structures 3.3.1 The efficiency of data sharing 3.3.2 Recursion over lists and generalizing to higher-order functions 3.3.3 More functions for working with lists 3.3.4 Loss of efficiency when assembling list functions from simpler components 3.4 Trees 3.5 Conclusion Summary 3.6 Exercise answers 4 Handling errors without exceptions 4.1 The good and bad aspects of exceptions 4.2 Possible alternatives to exceptions 4.3 The Option data type 4.3.1 Usage patterns for Option 4.3.2 Option composition, lifting, and wrapping exception-oriented APIs 4.4 The Either data type 4.4.1 Accumulating errors 4.4.2 Extracting a Validated type 4.5 Conclusion Summary 4.6 Exercise answers 5 Strictness and laziness 5.1 Strict and nonstrict functions 5.2 Lazy lists: An extended example 5.2.1 Memoizing lazy lists and avoiding recomputation 5.2.2 Helper functions for inspecting lazy lists 5.3 Separating program description from evaluation 5.4 Infinite lazy lists and corecursion 5.5 Conclusion Summary 5.6 Exercise answers 6 Purely functional state 6.1 Generating random numbers using side effects 6.2 Purely functional random number generation 6.3 Making stateful APIs pure 6.4 A better API for state actions 6.4.1 Combining state actions 6.4.2 Nesting state actions 6.5 A general state action data type 6.6 Purely functional imperative programming 6.7 Conclusion Summary 6.8 Exercise Answers Part 2. Functional design and combinator libraries 7 Purely functional parallelism 7.1 Choosing data types and functions 7.1.1 A data type for parallel computations 7.1.2 Combining parallel computations 7.1.3 Explicit forking 7.2 Picking a representation 7.2.1 Refining the API 7.3 The algebra of an API 7.3.1 The law of mapping 7.3.2 The law of forking 7.3.3 Breaking the law: A subtle bug 7.3.4 A fully non-blocking Par implementation using actors 7.4 Refining combinators to their most general form 7.5 Conclusion Summary 7.9 Exercise answers 8 Property-based testing 8.1 A brief tour of property-based testing 8.1.1 Choosing data types and functions 8.1.2 Initial snippets of an API 8.1.3 The meaning and API of properties 8.1.4 The meaning and API of generators 8.1.5 Generators that depend on generated values 8.1.6 Refining the Prop data type 8.2 Test case minimization 8.2.1 Using the library and improving its usability 8.2.2 Some simple examples 8.2.3 Writing a test suite for parallel computations 8.3 Testing higher-order functions and future directions 8.4 The laws of generators 8.5 Conclusion Summary 8.6 Exercise answers 9 Parser combinators 9.1 Designing an algebra first 9.2 A possible algebra 9.2.1 Slicing and nonempty repetition 9.3 Handling context sensitivity 9.4 Writing a JSON parser 9.4.1 The JSON format 9.4.2 A JSON parser 9.5 Error reporting 9.5.1 A possible design 9.5.2 Error nesting 9.5.3 Controlling branching and backtracking 9.6 Implementing the algebra 9.6.1 One possible implementation 9.6.2 Sequencing parsers 9.6.3 Labeling parsers 9.6.4 Failover and backtracking 9.6.5 Context-sensitive parsing 9.7 Conclusion Summary 9.8 Exercise answers Part 3. Common structures in functional design 10 Monoids 10.1 What is a monoid? 10.2 Folding lists with monoids 10.3 Associativity and parallelism 10.4 Example: Parallel parsing 10.5 Typeclasses 10.6 Foldable data structures 10.7 Composing monoids 10.7.1 Assembling more complex monoids 10.7.2 Using composed monoids to fuse traversals 10.8 Conclusion Summary 10.9 Exercise answers 11 Monads 11.1 Functors: Generalizing the map function 11.1.1 Functor laws 11.2 Monads: Generalizing the flatMap and unit functions 11.2.1 The Monad trait 11.3 Monadic combinators 11.4 Monad laws 11.4.1 The associative law 11.4.2 Proving the associative law for a specific monad 11.4.3 The identity laws 11.5 Just what is a monad? 11.5.1 The identity monad 11.5.2 The State monad and partial type application 11.6 Conclusion Summary 11.7 Exercise answers 12 Applicative and traversable functors 12.1 Generalizing monads 12.2 The Applicative trait 12.3 The difference between monads and applicative functors 12.3.1 The Option applicative versus the Option monad 12.3.2 The Parser applicative versus the Parser monad 12.4 The advantages of applicative functors 12.4.1 Not all applicative functors are monads 12.5 The applicative laws 12.5.1 Left and right identity 12.5.2 Associativity 12.5.3 Naturality of product 12.6 Traversable functors 12.7 Uses of Traverse 12.7.1 From monoids to applicative functors 12.7.2 Traversals with State 12.7.3 Combining traversable structures 12.7.4 Traversal fusion 12.7.5 Nested traversals 12.7.6 Monad composition 12.8 Conclusion Summary 12.9 Exercise answers Part 4. Effects and I/O 13 External effects and I/O 13.1 Factoring effects 13.2 A simple IO type 13.2.1 Handling input effects 13.2.2 Benefits and drawbacks of the simple IO type 13.3 Avoiding the StackOverflowError 13.3.1 Reifying control flow as data constructors 13.3.2 Trampolining: A general solution to stack overflow 13.4 A more nuanced I/O type 13.4.1 Free monads 13.4.2 A monad that supports only console I/O 13.4.3 Pure interpreters 13.5 Non-blocking and asynchronous I/O 13.5.1 Composing free algebras 13.6 Capabilities 13.7 A general-purpose I/O type 13.7.1 The main program at the end of the universe 13.8 Why the IO type is insufficient for streaming I/O 13.9 Conclusion Summary 13.10 Exercise answers 14 Local effects and mutable state 14.1 Purely functional mutable state 14.2 A data type to enforce the scoping of side effects 14.2.1 A little language for scoped mutation 14.2.2 An algebra of mutable references 14.2.3 Running mutable state actions 14.2.4 Mutable arrays 14.2.5 A purely functional in-place quicksort 14.3 Purity is contextual 14.3.1 What counts as a side effect? 14.4 Conclusion Summary 14.5 Exercise answers 15 Stream processing and incremental I/O 15.1 Problems with imperative I/O: An example 15.2 Simple stream transformations 15.2.1 Creating pulls 15.2.2 Composing stream transformations 15.2.3 Processing files 15.3 Extensible pulls and streams 15.3.1 Effectful streaming computations 15.3.2 Handling errors 15.3.3 Ensuring resource safety 15.3.4 Dynamic resource allocation 15.4 Applications 15.5 Conclusion Summary 15.6 Exercise answers index