10 Functional combinators for fluent concurrent programming

 

This chapter covers

  • Handling exceptions in a functional style
  • Using built-in Task combinators
  • Implementing custom asynchronous combinators and conditional operators
  • Running parallel asynchronous heterogeneous computations

In the previous two chapters, you learned how to apply asynchronous programming to develop scalable and performant systems. You applied functional techniques to compose, control, and optimize the execution of multiple tasks in parallel. This chapter further raises the level of abstraction for expressing asynchronous computations in a functional style.

We’ll start by looking at how to manage exceptions in a functional style, with a focus on asynchronous operations. Next, we’ll explore functional combinators, a useful programming tool for building a set of utility functions that allow you to create complex functions by composing smaller and more concise operators. These combinators and techniques make your code more maintainable and performant, improving your ability to write concurrent computations and handle side effects. Toward the end of this chapter, we’ll go through how to interop between C# and F# by calling and passing asynchronous functions from one to the other.

Of all the chapters in this book, this one is the most complex, because it covers FP theory where the lexicon might appear as jargon initially. With great effort, comes great reward . . . .

10.1 The execution flow isn’t always on the happy path: error handling

10.1.1 The problem of error handling in imperative programming

10.2.1 Error handling in FP: exceptions for flow control

10.2.2 Handling errors with Task<Option<T>> in C#

10.2.3 The F# AsyncOption type: combining Async and Option

10.2.4 Idiomatic F# functional asynchronous error handling

10.2.5 Preserving the exception semantic with the Result type

10.3 Taming exceptions in asynchronous operations

10.3.1 Modeling error handling in F# with Async and Result

10.3.2 Extending the F# AsyncResult type with monadic bind operators

10.4 Abstracting operations with functional combinators

10.5 Functional combinators in a nutshell

10.5.1 The TPL built-in asynchronous combinators

10.5.2 Exploiting the Task.WhenAny combinator for redundancy and interleaving

10.5.3 Exploiting the Task.WhenAll combinator for asynchronous for-each

10.5.4 Mathematical pattern review: what you’ve seen so far

What is the importance of laws?

10.6 The ultimate parallel composition applicative functor

10.6.1 Extending the F# async workflow with applicative functor operators

10.6.2 Applicative functor semantics in F# with infix operators

10.6.3 Exploiting heterogeneous parallel computation with applicative functors

10.6.4 Composing and executing heterogeneous parallel computations

10.6.5 Controlling flow with conditional asynchronous combinators

10.6.6 Asynchronous combinators in action

Summary