HaintonDotNet - Functional Programming in C# - Simon Painter

HaintonDotNet - Functional Programming in C# - Simon Painter

This article was originally published 22nd November 2022 on Linkedin

Or How I Learned to Stop Worrying and Love the Monad

Simon Painter has been using functional programming for many years and went over Who. What, Where, When and Why of Functional Programming.

Who is Functional Programming?

Haskell Curry is a well-known person in the functional programming space with the Haskell language being named after them along with John McCarthy who developed LISP for functional programming in the 1960s.

What is Functional Programming not?

It is not new, is not a framework - not here today and gone tomorrow and the first functional programming language was available in the 1960s and the first groundwork was done in the late 1800s. It isn't language, but a paradigm, which is a style of programming. Popular languages are imperative and declarative, where declarative is for functional programming. Functional programming is not the solution to all your problems, but it is not difficult unless you're ingrained into the object-oriented mindset as it is very different to what you are used to.

Declarative programming is oriented around the result and the order of the operations are, you are describing what you want, are not concerned with the order of the operations but what will be the outcome. Immutability is inherent so you write like a mathematical expression without replacing old values but creating new ones. There are higher-order functions such as a func delegate in C#. Functions and not statements are used in functional programming so things like while and if are not used. Functional programming also supports referential transparency, recursion, pattern matching, and it is also stateless.

Where is Functional Programming?

Functional Languages such as Haskell, Erlang, Elm etc. There are also hybrid languages such as Java, C# and Python along with F# which is the more functional language in the .NET family. JavaScript can also be used for Functional Programming as you can do anything there and can use something like Ramda JS.

When is Functional Programming?

Can use it for Data Processing and things like Concurrent Systems as it has no state so can run things in parallel. Functional programming is far more robust than object-oriented programming so is ideal for high-criticality systems and also works with serverless well.

When is Functional Programming not?

Functional programming has no side effects so cannot be used with UI such as users, web APIs and databases are unpredictable but those are the less functional areas and C# is not a pure functional programming language so have to make compromises.

Why is Functional Programming?

Functional programming is concise, the signal to noise ratio is good, which is what are you trying to achieve is the signal and the noise is all the things you have to add to get to where you need to go. In functional programming the code more closely models readable English. Predictable side-effect free code is very straightforward to being tested, can unit test things to a great degree and can have concurrency and can produce very robust code with Functional Programming.

Example of Functional Programming

LINQ is developed based on the functional paradigm so if you have been writing these then you have been using functional programming as these statements don't modify the data and use functions that are being passed to other functions as a parameter so moves towards declarative with the goal is to make the rest of C# look like this.

You could have multiple funcs that perform something like a regex for example on National Insurance numbers and then can have a collection of these for each check and then run each of these against the values which can then return true and then can use All in LINQ to then check up to the ones that fail and then the rest aren't executed and any new rules can be added to the list that are checked. You could use extension methods to encapsulate the behaviour needed to check for default values. Another function example is Fork which is where you start with a single value and feed this into the “prongs” of the fork and run a calculation on each of these and then have another part which will add these values together, so can write own map function which will operate on the entire object from one form to another.

Something you can do is have switch statements you can then switch on types which is good for generics but can use switch expressions to more closely match the functional paradigm and each version of C# now is starting to support more functional features such as tuples which were added before and also some features that have been added to F# have been added in C#. Recursion works well in F# but not so well in C# but other features can be shared.

Ideally in functional programming each variable should be immutable such as a class with read-only properties set on a constructor which means those values cannot be changed later, however if this is a list then this list itself can be manipulated. However, it is possible to now create Immutable Arrays so these can be modified, however you can have classes in a class but can make that one immutable, but it of course is possible to not do this. You do get warnings for nullable types but immutability in C# is just a pipe dream but even if all your code is like this then you'll have to use third-party libraries, but the best way is to pretend everything is immutable and treat it this way. You can also for properties use init and this will allow the property to be set when the object is created, they cannot be set again later for this same object and can help solve many issues with trying to enforce immutability. You can also have record types where you can have functional style updates, where you create a new object and copy over all the things you don't want to modify and anything you do into a new object which you can do with records to create a new object with a different value set where needed.

Currying allows you to get a function where the function is returned if only one of two parameters you get a function with just one of the parameters are set and then do this again you can add this value, you can't really do this in C#, but you can get close where you have an arrow function that returns a function which includes the value that was passed in. So could have a method that takes five parameters and then provide three and get back a function that will take two and has the three values passed in, essentially inheritance on the line level. However, in C# you can only do this with functions, but you could create Apply methods that reduce the parameters and return functions in this way.

In LINQ you can use Aggregate instead of a for loop which can run a function against every single item in the collection and can have accumulator values that can be updated and have the result of this being the total values and not have to use a for-loop. Or for something like a conversion you are updating values on after the other, so you can put values in a “box” and then have this value be adjusted and then put in another box and so on which is a structure known as a monad, which is kind of like a relay race, where you take a value and pass it on and the next one takes the value and does something to it then passes it on again. You could also have Either with a Left and Right so could have the last good value and an error if something went wrong, but can also have Something or has a value, Nothing or Error where there a problem.

There is LanguageExt which implements many functional programming structures for C# with functions such as Map and Match but can write your own and can modify them to be as needed be that the three states of Something, Nothing or Error or can have something more complicated as needed.