Functional Programming – C# Exercises

Learning Goals

  • Software design approaches and patterns, to identify reusable solutions to commonly occurring problems
  • Apply an appropriate software development approach according to the relevant paradigm (for example object oriented, event driven or procedural)

Programs Used

Apples

For this exercise, create a new dotnet console codebase by navigating to a new folder, and run dotnet new console.

Run dotnet run – the console should print Hello, World!.

Replace the contents of Program.cs with the following code:

IEnumerable<Apple> PickApples()
{
    int colourIndex = 1;
    int poisonIndex = 7;

    while (true)
    {
        yield return new Apple
        {
            Colour = GetColour(colourIndex),
            Poisoned = poisonIndex % 41 == 0
        };

        colourIndex += 5;
        poisonIndex += 37;
    }
}

string GetColour(int colourIndex)
{
    if (colourIndex % 13 == 0 || colourIndex % 29 == 0)
    {
        return "Green";
    }

    if (colourIndex % 11 == 0 || colourIndex % 19 == 0)
    {
        return "Yellow";
    }

    return "Red";
}

class Apple
{
    public string Colour { get; set; }
    public bool Poisoned { get; set; }

    public override string ToString()
    {
        return $"{Colour} apple{(Poisoned ? " (poisoned!)" : "")}";
    }
}

This (intentionally rather obtuse) block of code generates an infinite harvest of apples. Some of them have been poisoned. Use LINQ to answer the following questions about the first 10,000 apples:

  • How many apples are poisoned?
  • The majority of poisoned apples are Red. Which is the next most common colour for poisoned apples?
  • What’s the maximum number of non-poisoned Red apples that get picked in succession?
  • If you pick a Green apple, how many times will the next apple also be Green?

Try to solve the problems using a single C# expression (i.e. a single logical line of code). However still try to keep it readable – split that one line of code across several lines in your editor, and make sure any lambda expressions are easy to understand.

A “Functional” Gilded Rose

There is an established refactoring exercise called The Gilded Rose. We have made a slightly custom version of the exercise for you to complete. The original version is here.

Firstly, fork and clone the starter repo here to your machine and follow the instructions in the README. Your task is to follow a functional approach for rewriting the code. The requirements for the Gilded Rose can be found in your repo in the file gilded_rose_requirements.md.

The repository includes a “golden master” test, which is a simple snapshot test to check that your refactor hasn’t broken anything. It also includes a simple example test that can be used as a pattern if you want to implement more targeted unit tests.

You can run the tests with dotnet test.

Things you might want to consider improving:

  • The structure of the Gilded Rose class is very OOP currently, how could we convert that to be fundamentally more functional?
    • E.g. could we convert the update_quality function to be a “pure” function?
    • This may require changing the tests to follow the new pattern
  • Could we split up the handling of the quality & sell_in properties to be separate?
  • Could we reduce (or even eliminate!) any “assignment” operations (x = y) where state is being handled?
  • Could we split the logic to be more readable?