Grokking Functional Programming
- Length: 520 pages
- Edition: 1
- Language: English
- Publisher: Manning
- Publication Date: 2022-11-08
- ISBN-10: 1617291838
- ISBN-13: 9781617291838
- Sales Rank: #2287486 (See Top 100 Books)
Grokking Functional Programming is a practical book. Written especially for object-oriented programmers, it will help you map familiar ideas like objects and inheritance to FP concepts such as programming with immutable data, higher order functions, composing functions, concurrent programming and even the dreaded monad. And you’ll be pleased to know that we skip the academic baggage of lambda calculus, category theory, and the mathematical foundations of FP in favor of applying functional programming to everyday programming tasks. At the end of the book, you’ll be ready to pick a functional language and start writing useful software.
Functional Programming contents preface acknowledgments about this book about the authors Part 1 The functional toolkit 1 Learning functional programming Perhaps you picked up this book because... What do you need to know before we start? What do functions look like? Meet the function When the code lies... Imperative vs. declarative Coffee break: Imperative vs. declarative Coffee break explained: Imperative vs. declarative How useful is learning functional programming? Leaping into Scala Practicing functions in Scala Getting your tools ready Getting to know the REPL Writing your first functions! How to use this book 2 Pure functions Why do we need pure functions? Coding imperatively Breaking the code Passing copies of the data Breaking the code . . . again Recalculating instead of storing Focusing on the logic by passing the state Where did the state go? The difference between impure and pure functions Coffee break: Refactoring to a pure function Coffee break explained: Refactoring to a pure function In pure functions we trust Pure functions in programming languages Difficulty of staying pure... Pure functions and clean code Coffee break: Pure or impure? Coffee break explained: Pure or impure? Using Scala to write pure functions Practicing pure functions in Scala Testing pure functions Coffee break: Testing pure functions Coffee break explained: Testing pure functions 3 Immutable values The fuel for the engine Another case for immutability Can you trust this function? Mutability is dangerous Functions that lie... again Fighting mutability by working with copies Coffee break: Getting burned by mutability Coffee break explained: Getting burned by mutability Introducing shared mutable state State’s impact on programming abilities Dealing with the moving parts Dealing with the moving parts using FP Immutable values in Scala Building our intuition about immutability Coffee break: The immutable String API Coffee break explained: The immutable String API Hold on . . . Isn’t this bad? Purely functional approach to shared mutable state Practicing immutable slicing and appending 4 Functions as values Implementing requirements as functions Impure functions and mutable values strike back Using Java Streams to sort the list Function signatures should tell the whole story Changing requirements We just pass the code around! Using Java’s Function values Using the Function syntax to deal with code duplication Passing user-defined functions as arguments Coffee break: Functions as parameters Coffee break explained: Functions as parameters Problems with reading functional Java Passing functions in Scala Deep dive into sortBy Signatures with function parameters in Scala Passing functions as arguments in Scala Practicing function passing Embracing declarative programming Passing functions to custom-made functions Small functions and their responsibilities Passing functions inline Coffee break: Passing functions in Scala Coffee break explained: Passing functions in Scala What else can we achieve just by passing functions? Applying a function to each element of a list Applying a function to each element of a list using map Getting to know map Practicing map Learn once, use everywhere Returning parts of the list based on a condition Returning parts of the list using filter Getting to know filter Practicing filter Our journey so far... Don’t repeat yourself? Is my API easy to use? Adding a new parameter is not enough Functions can return functions Using functions that can return functions Functions are values Coffee break: Returning functions Coffee break explained: Returning functions Designing functional APIs Iterative design of functional APIs Returning functions from returned functions How to return functions from returned functions Using the flexible API built with returned functions Using multiple parameter lists in functions We have been currying! Practicing currying Programming by passing function values Reducing many values into a single value Reducing many values into a single one using foldLeft Getting to know foldLeft foldLeft must-knows Practicing foldLeft Modeling immutable data Using product types with higher-order functions More concise syntax for inline functions Part 2 Functional programs 5 Sequential programs Writing pipeline-based algorithms Composing larger programs from smaller pieces The imperative approach flatten and flatMap Practical use case of using more flatMaps flatMap and changing the size of the list Coffee break: Dealing with lists of lists Coffee break explained: Dealing with lists of lists Chained flatMaps and maps Nested flatMaps Values that depend on other values Practicing nested flatMaps A better syntax for nested flatMaps For comprehensions to the rescue! Coffee break: flatMaps vs. for comprehensions Coffee break explained: flatMaps vs. for comprehensions Getting to know for comprehensions It’s not the for you are looking for! Inside a for comprehension More sophisticated for comprehensions Checking all combinations using a for comprehension Filtering techniques Coffee break: Filtering techniques Coffee break explained: Filtering techniques Looking for a greater abstraction Comparing map, foldLeft, and flatMap Using for comprehensions with Sets Using for comprehensions with many types Practicing for comprehensions Defining for comprehensions... again Using for comprehensions with noncollection types Avoiding nulls: Option type Parsing as a pipeline Coffee break: Parsing with Option Coffee break explained: Parsing with Option 6 Error handling Handling lots of different errors, gracefully Is it even possible to handle them all? Sort the list of TV shows by their running time Implementing the sorting requirement Dealing with data coming from the outside world Functional design: Building from small blocks Parsing Strings into immutable objects Parsing a List is just parsing one element Parsing a String into a TvShow What about potential errors? Is returning null a good idea? How do we handle potential errors more gracefully? Implementing a function that returns an Option Option forces us to handle possible errors Building from small blocks Functional design is building from small blocks Writing a small, safe function that returns an Option Functions, values, and expressions Practicing safe functions that return Options How do errors propagate? Values represent errors Option, for comprehensions, and checked exceptions... What about checked exceptions? Conditional recovery Conditional recovery using the imperative style Checked exceptions don’t compose—Options do! How does orElse work? Practicing functional error handling Functions compose, even in the presence of errors Compiler reminds us that errors need to be covered Compilation errors are good for us! Transforming a List of Options into a flat List Let the compiler be our guide... ...but let’s not trust the compiler too much! Coffee break: Error-handling strategies Coffee break explained: Error-handling strategies Two different error-handling strategies All-or-nothing error-handling strategy Folding a List of Options into an Option of a List We now know how to handle multiple possible errors! How to know what failed We need to convey error details in the return value Conveying error details using Either Refactoring to Either Returning an Either instead of an Option Practicing safe functions that return Either What we learned about Option works with Either Coffee break: Error handling using Either Coffee break explained: Error handling using Either Working with Option/Either 7 Requirements as types Modeling data to minimize programmers’ mistakes Well-modeled data can’t lie Designing using what we know so far (which is primitive types) Using data modeled as primitive types Coffee break: The pain of primitive types Coffee break explained: The pain of primitive types Problems with the primitive type approach to modeling Using primitive types makes our jobs harder! Newtypes protect against misplaced parameters Using newtypes in data models Practicing newtypes Making sure only valid data combinations are possible Modeling possibility of absence in your data Changes in the model force changes in the logic Using data modeled as Options in your logic Higher-order functions for the win! There is probably a higher-order function for that! Coffee break: forall/exists/contains Coffee break explained: forall/exists/contains Coupling a concept inside a single product type Modeling finite possibilities Using sum types Even better modeling with sum types Using the sum type + product type combo Product types + sum types = algebraic data types (ADTs) Using ADT-based models in behaviors (functions) Destructuring ADTs using pattern matching Duplication and DRY Practicing pattern matching Newtypes, ADTs, and pattern matching in the wild What about inheritance? Coffee break: Functional data design Coffee break explained: Functional data design Modeling behaviors Modeling behaviors as data Implementing functions with ADT-based parameters Coffee break: Design and maintainability Coffee break explained: Design and maintainability 8 IO as values Talking to the outside world Integrating with an external API Properties of a side-effectful IO action Imperative solution to side-effecting IO code Problems with the imperative approach to IO Can we really do better using FP? Doing IO vs. using IO’s result Handling IO imperatively Computations as IO values IO values IO values in the wild Pushing the impurity out Using values fetched from two IO actions Combining two IO values into a single IO value Practicing creating and combining IO values Disentangling concerns by working with values only The IO type is viral Coffee break: Working with values Coffee break explained: Working with values Toward functional IO What about IO failures? Running a program described by IO may fail! Remember orElse? Lazy and eager evaluation Implementing recovery strategies using IO.orElse Implementing fallbacks using orElse and pure Practicing failure recovery in IO values Where should we handle potential failures? Toward functional IO with failure handling Pure functions don’t lie, even in the unsafe world! Functional architecture Using IO to store data Coffee break: Using IO to store data Coffee break explained: Using IO to store data Treating everything as values Treating retries as values Treating an unknown number of API calls as values Practicing functional signature intuitions 9 Streams as values To infinity and beyond Dealing with an unknown number of values Dealing with external impure API calls (again) The functional approach to the design Immutable maps Practicing immutable maps How many IO calls should we make? The bottom-up design Advanced list operations Introducing tuples Zipping and dropping Pattern matching on tuples Coffee break: Working with maps and tuples Coffee break explained: Working with maps and tuples Functional jigsaw puzzle Following types in a bottom-up design Prototyping and dead ends Recursive functions Infinity and laziness Recursive function structure Dealing with an absence in the future (using recursion) Usefulness of infinite recursive calls Coffee break: Recursion and infinity Coffee break explained: Recursion and infinity Creating different IO programs using recursion Using recursion to make an arbitrary number of calls Problems with the recursive version Introducing data streams Streams in imperative languages Values on demand Stream processing, producers, and consumers Streams and IO The functional Stream Streams in FP are values Streams are recursive values Primitive operations and combinators Streams of IO-based values Infinite streams of IO-based values Executing for side effects Practicing stream operations Using streams to our advantage Infinite stream of API calls Handling IO failures in streams Separated concerns Sliding windows Waiting between IO calls Zipping streams Benefits of using the stream-based approach 10 Concurrent programs Threads, threads everywhere Declarative concurrency Sequential vs. concurrent Coffee break: Sequential thinking Coffee break explained: Sequential thinking The need for batching Batching implementation The concurrent world The concurrent state Imperative concurrency Atomic references Introducing Ref Updating Ref values Using Ref values Making it all concurrent parSequence in action Practicing concurrent IOs Modeling concurrency Coding using Refs and fibers IOs that run infinitely Coffee break: Concurrent thinking Coffee break explained: Concurrent thinking The need for asynchronicity Preparing for asynchronous access Designing functional asynchronous programs Managing fibers manually Coding functional asynchronous programs Part 3 Applied functional programming 11 Designing functional programs Make it work, make it right, make it fast Modeling using immutable values Business domain modeling and FP Data access modeling A bag of functions Business logic as a pure function Separating the real data access concern Integrating with APIs using imperative libraries and IO Following the design Implementing input actions as IO values Separating the library IO from other concerns Currying and inversion of control Functions as values Connecting the dots We made it work Making it right Resource leaks Handling resources Using a Resource value We made it right Coffee break: Make it fast Coffee break explained: Make it fast 12 Testing functional programs Do you have tests for that? Tests are just functions Choosing functions to test Testing by providing examples Practicing testing by example Generating good examples Generating properties Property-based testing Testing by providing properties Delegating the work by passing functions Understanding failures of property-based tests Wrong test or a bug? Custom generators Using custom generators Testing more complicated scenarios in a readable way Finding and fixing bugs in the implementation Coffee break: Property-based tests Coffee break explained: Property-based tests Properties and examples Requirements coverage Testing side-effectful requirements Identifying the right test for the job Data usage tests Practicing stubbing external services using IO Testing and design Service integration tests Local servers as Resources in integration tests Writing isolated integration tests Integration with a service is a single responsibility Coffee break: Writing integration tests Coffee break explained: Writing integration tests Integration tests take more time Property-based integration tests Choosing the right testing approach Test-driven development Writing a test for a feature that doesn’t exist Red green refactor Making tests green Adding more red tests The last TDD iteration Appendix A: Scala cheat sheet Appendix B: Functional gems index A B C D E F G H I J L M N O P Q R S T U V W Y Z
Donate to keep this site alive
1. Disable the AdBlock plugin. Otherwise, you may not get any links.
2. Solve the CAPTCHA.
3. Click download link.
4. Lead to download server to download.