Functional Programming in C#
Enrico Buonanno
  • MEAP began May 2016
  • Publication in Summer 2017 (estimated)
  • ISBN 9781617293955
  • 325 pages (estimated)
  • printed in black & white

Functional programming is a way of thinking about programs that emphasizes functions, while avoiding state mutation. It allows us to write elegant, intention-revealing code, that shines in testability and support for concurrency. C# includes a number of functional features and libraries, enabling us to take advantage of these benefits.

Functional Programming in C# teaches you to apply functional thinking to real-world scenarios. You'll start by learning the principles of functional programming, and how they translate in the C# language. The book then dives into important topics like function composition, data flow, and principles for designing function signatures, types and collections. Through lots of real-world examples, you'll acquire the tools to tackle programming tasks with a functional approach. The last part of the book deals with advanced topics, including lazy evaluation, stateful computations, asynchrony, and event streams. By the end of this book, you'll be able to integrate functional techniques, making your C# programs robust and maintainable, and helping you become a more well-rounded developer.

"Amazing book for people who know C# and are looking to learn more as well as people who are interested in being more productive and improving their programing skills. Seriously, I can't wait to get my copy."

~ Gonzalo Barba Lopez

"If you are wanting to dip your toes into functional programming, learn techniques for applying FP in C#, or just want to be a better programmer, you should read this."

~ Devon Burriss

Table of Contents detailed table of contents

1. Introducing functional programming

1.1. What is this thing called functional programming?

1.1.1. Functions as 1st-class values

1.1.2. Avoiding state mutation

1.1.3. Writing programs with strong guarantees

1.2. How functional a language is C#?

1.2.1. The functional nature of LINQ

1.2.2. Functional features in C#6

1.2.3. A more Functional features in C#7

1.3. Thinking in functions

1.3.1. Functions as maps

1.3.2. Representing functions in C#

1.4. Higher-order functions

1.4.1. Functions that depend on other functions

1.4.2. Adapter functions

1.4.3. Function factories

1.5. In practice: avoiding duplication with HOFs

1.5.1. Encapsulating setup and teardown into a HOF

1.5.2. Turning the using statement into a HOF

1.5.3. Code review: tradeoffs of HOFs

1.6. Benefits of functional programming

1.7. Exercises

1.8. Summary

2. Why function purity matters

2.1. What is function purity?

2.1.1. Purity and side effects

2.1.2. Strategies for managing side effects

2.2. Purity and concurrency

2.2.1. Pure functions parallelize well

2.2.2. Parallelizing impure functions

2.2.3. Avoiding state mutation

2.3. Purity and Testability

====In practice: a validation scenario ==== Bringing impure functions under test ==== Why testing impure functions is hard ==== Parameterized unit tests ==== Avoiding header interfaces === Purity in the context of changes in computing === Exercises === Summary

3. Designing function signatures and types

3.1. Function signature design

3.1.1. Arrow notation

3.1.2. How informative is a signature?

3.2. Capturing data with data objects

3.2.1. Primitive types are often not specific enough

3.2.2. Constraining inputs with custom types

3.2.3. Writing "honest" functions

3.2.4. Composing values with tuples and objects

3.3. Modelling the absence of data with Unit

3.3.1. Why using void is not ideal

3.3.2. Bridging the gap between Action and Func with Unit

3.4. Modelling the possible absence of data with Option

3.4.1. The bad APIs you use every day

3.4.2. An introduction to the Option type

3.4.3. Implementing Option

3.4.4. Gaining robustness by using Option instead of null

3.4.5. Option as the natural result type of partial functions

3.5. Exercises

3.6. Summary

4. Patterns in Functional Programming

4.1. Applying a function to the inner values of a structure

4.1.1. Mapping a function onto a sequence of values

4.1.2. Mapping a function onto an optional value

4.1.3. Introducing Functors

4.2. Performing side effects with ForEach

4.3. The Bind function

4.3.1. Composing Option-returning functions with Bind

4.4. Flattening nested lists with Bind

4.4.1. Actually, it's called a monad

4.4.2. The Return function

4.4.3. Relation between functors and monads

4.5. Filtering values with Where

4.6. Combining Option and IEnumerable with Bind

4.7. Coding at different levels of abstraction

4.7.1. Regular vs elevated values

4.7.2. Crossing levels of abstraction

4.7.3. Map vs Bind, revisited

4.7.4. Working at the right level of abstraction

4.8. Exercises

4.9. Summary

5. Designing programs with function composition

5.1. Function composition

5.1.1. Brushing up on function composition

5.1.2. Method chaining

5.1.3. Composition in the elevated world

5.2. Thinking in terms of data flow

5.2.1. Using LINQ's composable API

5.2.2. Writing functions that compose well

5.3. Programming workflows

5.3.1. A simple workflow for validation

5.3.2. Refactoring with data flow in mind

5.3.3. Composition leads to greater flexibility

5.4. An introduction to functional domain modelling

5.5. An end-to-end server-side workflow

5.5.1. Expressions vs statements

5.5.2. Declarative vs imperative

5.5.3. The functional take on layering

5.6. Exercises

5.7. Summary

6. Functional error handling

6.1. A safer way to represent outcomes

6.1.1. Capturing error details with Either

6.1.2. Core functions for working with Either

6.1.3. Comparing Option and Either

6.2. Chaining operations that may fail

6.3. Validation: a perfect use case for Either

6.3.1. Choosing a suitable representation for errors

6.3.2. Defining an Either-based API

6.3.3. Adding validation logic

6.4. Representing outcomes to client applications

6.4.1. Exposing an Option-like interface

6.4.2. Exposing an Either-like interface

6.4.3. Returning a result DTO

6.5. Variations on the Either theme

6.5.1. Changing between different representations of errors

6.5.2. Specialized versions of Either

6.5.3. Refactoring to Validation and Exceptional

6.5.4. Leaving exceptions behind?

6.6. Exercises

6.7. Summary

7. Structuring an application with functions

7.1. Partial application: supplying arguments piecemeal

7.1.1. Manually enabling partial application

7.1.2. Generalizing partial application

7.1.3. Order of arguments matters

7.2. Overcoming the quirks of method resolution

7.3. Curried functions: optimized for partial application

7.4. Creating a partial-application-friendly API

7.4.1. Types as documentation

7.4.2. Particularizing the data access function

7.5. Modularizing and composing an application

7.5.1. Modularity in OOP

7.5.2. Modularity in FP

7.5.3. Comparing the two

7.5.4. Composing the application

7.6. Reducing a list to a single value

7.6.1. LINQ's Aggregate method

7.6.2. Aggregating validation results

7.6.3. Harvesting validation errors

7.7. Exercises

7.8. Summary

8. Working effectively with multi-argument functions

8.1. Function application in the elevated world

8.1.1. Understanding applicatives

8.1.2. Lifting functions

8.1.3. An introduction to property testing

8.2. Functors, Applicatives, Monads

8.3. The monad laws

8.3.1. Right identity

8.3.2. Left identity

8.3.3. Associativity

8.3.4. Using Bind with multi-argument functions

8.4. Improving readability by using LINQ with any monad

8.4.1. Using LINQ with arbitrary functors

8.4.2. Using LINQ with arbitrary monads

8.4.3. Let, Where and other LINQ clauses

8.5. In practice: when to use Bind vs Apply

8.5.1. Validation with smart constructors

8.5.2. Harvesting errors with the applicative flow

8.5.3. Failing fast with the monadic flow

8.6. Exercises

8.7. Summary

9. Thinking about data functionally

9.1. The pitfalls of state mutation

9.2. Understanding state, identity, and change

9.2.1. Some things never change

9.2.2. Representing change without mutation

9.2.3. Enforcing immutability

9.3. A short introduction to functional data structures

9.3.1. The classic functional linked list

9.3.2. Binary trees

9.4. Exercises

9.5. Summary

10. Event sourcing: a functional approach to data persistence

10.1. Thinking functionally about data storage

10.1.1. Why data storage should be append-only

10.1.2. Relax, and forget about storing state

10.2. Event sourcing basics

10.2.1. Representing events

10.2.2. Persisting events

10.2.3. Representing state

10.2.4. An interlude on pattern matching

10.2.5. Representing state transitions

10.2.6. Reconstructing current state from past events

10.3. Architecture of an event sourced system

10.3.1. Handling commands

10.3.2. Handling events

10.3.3. Adding validation

10.3.4. Creating views of the data from events

10.4. Comparing different approaches to immutable storage

10.4.1. Datomic vs Event Store

10.4.2. How event-driven is your domain?

10.5. Summary

11. Lazy computations, continuations, and other composable gems

11.1. The virtue of lazyness

11.1.1. A lazy APIs for Option

11.1.2. Composing lazy computations

11.2. Error handling with Try

11.2.1. Representing computations that may fail

11.2.2. Composing computations that may fail

11.2.3. Safely extracting information from a JSON object

11.3. Programs that manage state

11.3.1. Maintaining a cache of retrieved resources

11.3.2. Refactoring for testability and error handling

11.4. Chaining stateful computations

11.4.1. Generating random numbers

11.4.2. Generating complex random structures

11.4.3. A general pattern for stateful computations

11.5. Creating a middleware pipeline for DB access

11.5.1. Composing functions that perform setup/teardown

11.5.2. A recipe against the pyramid of doom

11.5.3. Capturing the essence of a middleware function

11.5.4. Implementing the query pattern for Middleware

11.5.5. Adding middleware that times the operation

11.5.6. Adding middleware that manages a DB transaction

11.6. Summary

12. Working with asynchronous computations

12.1. Asynchronous computations

12.1.1. The need for asynchrony

12.1.2. Representing asynchronous operations with Task

12.1.3. Task as a container for a future value

12.1.4. Handling failure

12.1.5. If it fails, try a few more times

12.1.6. Running asynchronous operations in parallel

12.2. Traversables: working with lists of elevated values

12.2.1. Validating a list of values with monadic Traverse

12.2.2. Harvesting validation errors with applicative Traverse

12.2.3. Applying multiple validators to a single value

12.2.4. Using Traverse with Task to await multiple results

12.2.5. Defining Traverse for single-value structures

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

12.3.1. The problem of stacked monads

12.3.2. Reducing the number of effects

12.3.3. LINQ expressions with a monad stack

12.4. Summary

13. Data streams and the Reactive Extensions

14. An introduction to message-passing concurrency

What's inside

  • Introduction to functional programming and design
  • Explore C#'s functional programming capabilities
  • Understand how function purity improves testability and support for concurrency
  • Write more readable, declarative code by writing functions that compose
  • Adopt a new approach to error handling and managing state
  • Embrace event-driven design and immutability
  • Leverage concurrency without the pitfalls of shared mutable state
  • Apply functional programming to solve real-world problems

About the reader

This book is designed to help C# programmers with an OOP background understand functional thinking.

About the author

Enrico Buonanno obtained an MS in Computer Science at Columbia University in 2001 and has been working as a software developer and architect since. Working on mission-critical applications in FinTech and other technology-driven businesses has given him a thorough understanding of the demands made on enterprise applications, and how to respond to them with modern designs and techniques.

Manning Early Access Program (MEAP) Read chapters as they are written, get the finished eBook as soon as it’s ready, and receive the pBook long before it's in bookstores.
MEAP combo $49.99 pBook + eBook
MEAP eBook $39.99 pdf + ePub + kindle

FREE domestic shipping on three or more pBooks