17 Traversable and stacked monads

 

This chapter covers

  • Traversables: handling lists of elevated types
  • Combining the effects of different monads

So far in the book you’ve seen a number of different containers that add some effect to the underlying value(s)—Option for optionality, IEnumerable for aggregation, Task for asynchrony, and so on. As our list of containers keeps growing, we’ll inevitably hit the problem of combining different containers:

  • If you have a list of Tasks that you want to execute, how can you combine them into a single Task that will complete when all the operations have completed?
  • If you have a value of type Task<Validation<T>>, how do you compose it with a function of type T Task<R> with the least amount of noise?

This chapter will give you the tools to combine the effects of different containers and show how to avoid an excess of nested containers.

17.1 Traversables: Working with lists of elevated values

Traverse is one of the slightly more esoteric core functions in FP, and it allows you to work with lists of elevated values. It’s probably easiest to approach through an example.

Imagine a simple command-line application that reads a comma-separated list of numbers entered by the user and returns the sum of all the given numbers. We could start along these lines:

17.1.1 Validating a list of values with monadic Traverse

17.1.2 Harvesting validation errors with applicative Traverse

17.1.3 Applying multiple validators to a single value

17.1.4 Using Traverse with Task to await multiple results

17.1.5 Defining Traverse for single-value structures

17.2 Combining asynchrony and validation (or any other two monadic effects)

17.2.1 The problem of stacked monads

17.2.2 Reducing the number of effects

17.2.3 LINQ expressions with a monad stack