csharp-language-ext

Functional Programming in C# with the LanguageExt library

  • 4 min

LanguageExt is a functional language extensions library for C#. It was created by Paul Louth and aims to facilitate working with functional features in C#, such as functional programming and immutability.

LanguageExt is based on functional programming best practices and provides a wide range of data structures and functions to help developers write cleaner, more concise, and safer code.

LanguageExt provides a wide range of functional features for C#, including:

  • Immutable data structures, such as lists and maps.
  • Higher-order functions, like map and fold.
  • Asynchronous programming with support for cancellation and exceptions.
  • Option and Result types to avoid runtime exceptions.
  • A concurrency system based on agents and channels.

This library is not small. Quite the opposite, it’s a huge library that provides a vast amount of tools that represent a significant change in how C# is used.

However, logically, you don’t need to use all the tools all the time. LanguageExt presents itself as a collection of utilities that are beneficial to use on certain occasions.

On the other hand, many of the features offered by LanguageExt have been progressively incorporated into .NET versions, which follows its own evolution towards more functional paradigms.

Personally, I also see this library as a “testing ground” for new possibilities and trends in software development, in addition to providing certain practical utilities that do have immediate use.

How to use Language-ext

We can easily add the library to a .NET project via the corresponding Nuget package.

Install-Package LanguageExt.Core

Here are some examples of how to use Language-ext extracted from the library’s documentation.

Null

We can manage Null objects easily thanks to Option<T>

var optional = Some(123);

int x = optional
        .Some( v  => v * 2 )
        .None( () => 0 );

int x = optional.IfNone(10);  
Copied!

Matching

Using Option<T> along with matching.

Option<int> two = Some(2);
Option<int> four = Some(4);
Option<int> six = Some(6);
Option<int> none = None;

int r = match( from x in two
                from y in four
                from z in six
                select x + y + z,
                Some: v => v * 2,
                None: () => 0 );     // r == 24
Copied!

Out parameters

Avoid using Out parameters by using Option<T>

int res = parseInt("123").IfNone(0);

int res = parseInt("123").Match(
                Some: x => x * 2,
                None: () => 0
            );
Copied!

Unit

Unit data type to avoid using void to indicate the absence of a type.

public static Func<string, Unit> GetConsoleWrite() => fun<string>(Console.Write);
public static Func<string, Task<Unit>> GetConsoleWriteAsync() => (string v) => Console.Out.WriteAsync(v).ToUnit();

public static Unit WriteToConsole(string v) => fun(() => Console.Write(v))();
public static Task<Unit> WriteToConsoleAsync(string v) => Console.Out.WriteAsync(v).ToUnit(); 
Copied!

Collections

It also offers immutable collections, such as lists and maps.

var test = List(1, 2, 3, 4, 5);
var list = Range(500,1000);

var res = List(1, 2, 3, 4, 5)
            .Map(x => x * 10)
            .Filter(x => x > 20)
            .Fold(0, (x, s) => s + x);
Copied!

Or, for example, immutable dictionaries.

var dict = Map<string,int>();

var people = Map((1, "Rod"),
                (2, "Jane"),
                (3, "Freddy"));

Option<string> result = find(people, 1);

var res = match( find(people, 100),
                    Some: v  => "Hello " + v,
                    None: () => "failed" );
Copied!

Functions

Defining functions under a more functional paradigm.

public int Sum(IEnumerable<int> list) => match( list,
            ()      => 0,
            (x, xs) => x + Sum(xs)
);
Copied!

These are just examples of some of the functionalities. But the library offers many, many (many!) features. Take a look at the documentation because it’s really interesting, even if just as a source of inspiration and ideas.