Chapter 11. Refactoring and testing functional programs

 

This chapter covers

  • Refactoring functional programs
  • Reasoning about code using immutability
  • Writing unit tests for F# programs
  • Caching results using lazy values

One theme of this book is that functional programming makes it easier to understand code just by reading it. This is particularly important when you need to modify an unfamiliar program or implement behavior by composing existing functions or when refactoring existing code. Functional programming makes refactoring easier thanks to both clarity and modularity: you can make improvements to the code and be confident that the change doesn’t break other parts of the program.

As with many things in functional programming, the idea of modifying code without changing its meaning is closely related to math, because operations that don’t change the meaning of an expression are the basis of many mathematical tasks. We can take a complex equation and simplify it to get an equation that’s easier to read but means the same thing. Let’s take the following equation: y = 2x + 3(5 - x). If we multiply the expression in parentheses by 3, we can write it as y = 2x + 15 - 3x, which in turn can be simplified to: y = 15 – x.

11.1. Refactoring functional programs

11.1.1. Reusing common code blocks

11.1.2. Tracking dependencies and side effects

11.2. Testing functional code

11.2.1. From the interactive shell to unit tests

11.2.2. Writing tests using structural equality

11.2.3. Testing composed functionality

11.3. Refactoring the evaluation order

11.3.1. Different evaluation strategies

11.3.2. Comparing evaluation strategies

11.3.3. Simulating lazy evaluation using functions

11.3.4. Lazy values in F#

11.3.5. Implementing lazy values for C#

11.4. Using lazy values in practice

11.4.1. Introducing infinite lists

11.4.2. Caching values in a photo browser

11.5. Summary