🪟 Windows TippsMicrosoft Account Passkey not working [Fix](15.09.2026 um 14:36 Uhr)
🪟 Windows TippsDie neue Apple Watch mit Windows Recall?(15.09.2026 um 16:44 Uhr)
🪟 Windows TippsWindows 11 update breaks copy and paste in Microsoft Excel(15.09.2026 um 17:39 Uhr)
🪟 Windows ServerBSI warnt vor GitLab-Angriffswelle - IT-Administrator.de(15.09.2026 um 13:38 Uhr)
🪟 Windows TippsMicrosoft Account Passkey not working [Fix](15.09.2026 um 14:36 Uhr)
🪟 Windows TippsDie neue Apple Watch mit Windows Recall?(15.09.2026 um 16:44 Uhr)
🪟 Windows TippsWindows 11 update breaks copy and paste in Microsoft Excel(15.09.2026 um 17:39 Uhr)
🪟 Windows ServerBSI warnt vor GitLab-Angriffswelle - IT-Administrator.de(15.09.2026 um 13:38 Uhr)

🔧 Programmierung 🕛 vor 1 Jahr 33 Min Lesezeit
0

Functional Programming in C#

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht





Introduction



Functional programming is a programming paradigm based on functions, their compositions, and also on decomposition into functions.



There are two possible properties of functions:




  1. Purity: Functions have results that depend strictly on their arguments, with no other side effect. Purity leads to compartmentalization, localization, stability, and determinism.

  2. First-class citizenship: Functions have value status. Functions can be named, assigned, typed, created on demand, passed as an argument to a function, be the result of a function, and stored in a data structure. First-class citizenship leads to flexibility of use and compositionality.



Functional programming consists in exploiting one and/or the other of these two properties.



C# supports functional programming concepts, though it's primarily an object-oriented language. Here are the main functional programming features supported in C#:





  • First-class functions: lambda expressions, delegates, method references


  • Immutability: records, immutable collections, readonly members


  • Pure functions: methods without side effects, deterministic outputs


  • Higher-order functions: LINQ operations, methods that take functions as parameters


  • Pattern matching: switch expressions, property patterns, type patterns


  • Expression trees: represent code as data, used extensively in LINQ providers



This article will not discuss the basics of functional programming, as you can find numerous resources on this topic. Instead, it will talk about functional programming in C# applied to algebra, numbers, the Euclidean plane, and fractals. The examples provided in this article will start from simple to more complex but always illustrated in a simple, straightforward and easy-to-understand manner.






Development Environment



To run the source code, you will need to install




  • Functional.Core is a class library that contains sets functions and helpers.

  • Functional.Core.WPF is a WPF class library that contains plane and fractals functions and helpers.

  • Functional.EuclideanPlane is a WPF application that contains Euclidean Plane and Fractals samples.

  • Functional.Laziness is a Console application that contains Laziness samples.

  • Functional.Set is a Console application that contains sets samples.

  • Functional.UnitTests is the unit tests project.



To run numbers demo, run Functional.Set project.



To run Euclidean plane and fractals demos, run Functional.EuclideanPlane project.



To run laziness demo, run Functional.Laziness project.



To run unit tests, run the following command:




CODE
cd functional-cs/tests/Functional.UnitTests
dotnet test









Representing Data Through Functions



Let S be any set of elements a, b, c ... (for instance, the books on the table, or the videos in YouTube, or the points of the Euclidean plane) and let S' be any subset of these elements (for instance, the green books on the table, or the cultural videos in YouTube, or the points in the circle of radius 1 centered at the origin of the Euclidean plane).



The



Let E be the empty set and Empty its Characteristic function. In algebra of sets, E is the unique set having no elements. Therefore, Empty can be defined as follows:




CODE
Empty(x) = false if x is in E
Empty(x) = false if x is not in E






Thus, the representation of E in C# can be defined as follows:




CODE
public static Predicate<T> Empty<T>() => _ => false;






In algebra of sets, Empty is represented as follows:








Set All





Thus, running the code below:




CODE
Console.WriteLine("Is 7 in the integers set? {0}", All<int>()(7));






gives the following results:








Other Sets



This section presents subsets of the integers set.






Even numbers


Let E be the set of even numbers and Even its Characteristic function. In mathematics, an even number is a number which is a multiple of two. Therefore, Even can be defined as follows:




CODE
Even(x) = true if x is a multiple of 2
Even(x) = false if x is not a multiple of 2






Thus, the representation of E in C# can be defined as follows:




CODE
Predicate<int> even = i => i % 2 == 0;






Thus, running the code below:




CODE
Console.WriteLine("Is {0} even? {1}", 99, even(99));
Console.WriteLine("Is {0} even? {1}", 998, even(998));






gives the following results:








Multiples of 3


Let E be the set of multiples of 3 and MultipleOfThree its Characteristic function. In mathematics, a multiple of 3 is a number divisible by 3. Therefore, MultipleOfThree can be defined as follows:




CODE
MultipleOfThree(x) = true if x is divisible by 3
MultipleOfThree(x) = false if x is not divisible by 3






Thus, the representation of E in C# can be defined as follows:




CODE
Predicate<int> multipleOfThree = i => i % 3 == 0;






Thus, running the code below:




CODE
Console.WriteLine("Is {0} a multiple of 3? {1}", 99, multipleOfThree(99));
Console.WriteLine("Is {0} a multiple of 3? {1}", 998, multipleOfThree(998));






gives the following results:








Prime Numbers


A long time ago, when I was playing with






Binary Operations



This section presents several fundamental operations for constructing new sets from given sets and for manipulating sets. Below is the






Union








Intersection








Cartesian Product








Complements








Symmetric Difference








Other Operations



This section presents other useful binary operations on sets.






Contains


Let Contains be the operation that checks whether or not an element is in a set. This operation is an extension function on the Characteristic function of a set that takes as parameter an element and returns true if the element is in the set, false otherwise.



Thus, this operation is defined as follows in C#:




CODE
public static bool Contains<T>(this Predicate<T> e, T x) => e(x);






Therefore, running the code below:




CODE
Console.WriteLine("Is 7 in the singleton {{0}}? {0}", Singleton(0).Contains(7));
Console.WriteLine("Is 7 in the singleton {{7}}? {0}", Singleton(7).Contains(7));






gives the following result:








Remove


Let Remove be the operation that removes an element from a set. This operation is an extension function on the Characteristic function of a set that takes as parameter an element and removes it from the set.



Thus, this operation is defined as follows in C#:




CODE
public static Predicate<T> Remove<T>(this Predicate<T> s, T e) where T : notnull
=> x => !x.Equals(e) && s(x);






Therefore, running the code below:




CODE
Console.WriteLine("Is 7 in {{}}? {0}", Singleton(0).Remove(0)(7));
Console.WriteLine("Is 0 in {{}}? {0}", Singleton(7).Remove(7)(0));






gives the following result:





A disk is a subset of a plane bounded by a circle. There are two types of disks. Closed disks which are disks that contain the points of the circle that constitutes its boundary, and Open disks which are disks that do not contain the points of the circle that constitutes its boundary.



In this section, we will set up the Characterstic function of the Closed disk and draw it in WPF.



To set up the Characterstic function, we need first a function that calculates the Euclidean Distance between two points in the plane. This function is implemented as follows:




CODE
private static double EuclidianDistance(Point point1, Point point2)
=> Math.Sqrt(Math.Pow(point1.X - point2.X, 2) + Math.Pow(point1.Y - point2.Y, 2));






where Point is a struct defined in the System.Windows namespace. This formula is based on Pythagoras' Theorem.





where a and b are the coordinates of the center and R the radius.



Thus, the implementation of Disk in C# is as follows:




CODE
public static Predicate<Point> Disk(Point center, double radius)
=> p => EuclidianDistance(center, p) <= radius;






In order to view the set in a result, I decided to implement a function Draw that draws a set in the Euclidean plane. I chose WPF and thus used the System.Windows.Controls.Image as a canvas and a Bitmap as the context.



Thus, I've built the Euclidean plane illustrated below through the method Draw.








Drawing Horizontal and Vertical Half-Planes





Let VerticalHalfPlane be the Characteristic function of a vertical half-plane. The implementation of VerticalHalfPlane in C# is as follows:




CODE
public static Predicate<Point> VerticalHalfPlane(double x, bool lowerThan)
=> p => lowerThan ? p.X <= x : p.X >= x;






Thus, running the code below:




CODE
Plane.VerticalHalfPlane(0, false).Draw(PlaneCanvas);






gives the following result:








Functions



This section presents functions on the sets in the Euclidean plane.






Translate








Homothety





Thus the implementation in C# is as follows:




CODE
private static Func<Point, Point> Scale
(double deltax, double deltay, double lambdax, double lambday)
=> p => new Point(lambdax * p.X + deltax, lambday * p.Y + deltay);






where (deltax, deltay) is the constant vector of the translation and (lambdax, lambday) is the λ vector.



Let ScaleSet be the function that applies an homothety on a set in the plan. This function is simply implemented as follows in C#:




CODE
public static Predicate<Point> ScaleSet
(this Predicate<Point> set, double deltax, double deltay, double lambdax,
double lambday) =>
x => set(Scale(-deltax / lambdax, -deltay / lambday, 1 / lambdax, 1 / lambday)(x));






ScaleSet is an extension function on a set. It takes as parameters deltax which is the delta distance in the first Euclidean dimension, deltay which is the delta distance in the second Euclidean dimension and (lambdax, lambday) which is the constant factor vector λ. If a point P (x, y) is transformed through ScaleSet in a set S, then its coordinates will change to (x', y') = (lambdax * x + delatx, lambday * y + deltay). Thus, the point ((x'- delatx)/lambdax, (y' - deltay)/lambday) will always belong to the set S, If λ is different from the vector 0, of course. In algebra of sets, ScaleSet is called isomorph, in other words the set of all homotheties forms the Homothety group H, which is isomorphic to the space itself \ {0}. This explains the main logic of the function.



Thus, running the code below in our WPF application:




CODE
ScaleDiskAnimation();






where ScaleDiskAnimation is described below:




CODE
private const double Delta = 50;
private double _lambdaFactor = 1;
private double _diskScaleDeltay;
private readonly Predicate<Point> _disk2 = Plane.Disk(new Point(0, -230), 20);

private void ScaleDiskAnimation()
{
DispatcherTimer scaleTimer = new DispatcherTimer
{ Interval = new TimeSpan(0, 0, 0, 1, 0) };
scaleTimer.Tick += ScaleTimer_Tick;
scaleTimer.Start();
}

private void ScaleTimer_Tick(object? sender, EventArgs e)
{
_diskScaleDeltay = _diskScaleDeltay <= plan.Height ?
_diskScaleDeltay + Delta : Delta;
_lambdaFactor = _diskScaleDeltay <= plan.Height ? _lambdaFactor + 0.5 : 1;
Predicate<Point> scaledDisk = _diskScaleDeltay <= plan.Height
? _disk2.ScaleSet(0, _diskScaleDeltay,
_lambdaFactor, 1)
: _disk2;
scaledDisk.Draw(PlaneCanvas);
}






gives the following result:





Let Rotation be the function that rotates a point with an angle θ. In matrix algebra, Rotation is formulated as follows:





The demonstration of this formula is very simple. Have a look at this rotation.





Thus the implementation in C# is as follows:




CODE
private static Func<Point, Point> Rotate(double theta)
=> p => new Point(p.X * Math.Cos(theta) - p.Y * Math.Sin(theta),
p.X * Math.Sin(theta) + p.Y * Math.Cos(theta));






Let RotateSet be the function that applies a rotation on a set in the plane with the angle θ. This function is simply implemented as follow in C#.




CODE
public static Predicate<Point> RotateSet(this Predicate<Point> set, double theta)
=> p => set(Rotate(-theta)(p));






RotateSet is an extension function on a set. It takes as parameter theta which is the angle of the rotation. If a point P (x, y) is transformed through RotateSet in a set S, then its coordinates will change to (x', y') = (x * cos(θ) - y * sin(θ), x * cos(θ) + y * sin(θ)). Thus, the point (x' * cos(θ) + y' * sin(θ), x' * cos(θ) - y' * sin(θ)) will always belong to the set S. In algebra of sets, RotateSet is called isomorph, in other words, the set of all rotations forms the Rotation group R, which is isomorphic to the space itself. This explains the main logic of the function.



Thus, running the code below in our WPF application:




CODE
RotateHalfPlaneAnimation();






where RotateHalfPlaneAnimation is described below:




CODE
private double _theta;
private const double TWO_PI = 2 * Math.PI;
private const double HALF_PI = Math.PI / 2;
private readonly Predicate<Point> _halfPlane = Plane.VerticalHalfPlane(220, false);

private void RotateHalfPlaneAnimation()
{
DispatcherTimer rotateTimer =
new DispatcherTimer { Interval = new TimeSpan(0, 0, 0, 1, 0) };
rotateTimer.Tick += RotateTimer_Tick;
rotateTimer.Start();
}

private void RotateTimer_Tick(object? sender, EventArgs e)
{
_halfPlane.RotateSet(_theta).Draw(PlaneCanvas);
_theta += HALF_PI;
_theta %= TWO_PI;
}






gives the following result:





Fractals are sets that have a fractal dimension that usually exceeds their topological dimension and may fall between the integers. For example, the Mandelbrot set is a fractal defined by a family of complex quadratic polynomials:




CODE
Pc(z) = z^2 + c






where c is a complex. The Mandelbrot fractal is defined as the set of all points c such that the above sequence does not escape to infinity. In algebra of sets, this is formulated as follows:



.






Mandelbrot Fractal



I've created a Mandelbrot (abstract data type representation) P(z) = z^2 + c that is available below.




CODE
public static Func<Complex, Complex, Complex> MandelbrotFractal() => (c, z) => z * z + c;






In order to be able to draw Complex numbers, I needed to update the Draw function. Thus, I created an overload of the Draw function that uses ColorMap and ClorTriplet classes. Below is the implementation in C#.




CODE
public static void Draw(this Func<Complex, Complex> fractal, Image plane)
{
var bitmap = new Bitmap((int)plane.Width, (int)plane.Height);

const double reMin = -3.0;
const double reMax = +3.0;
const double imMin = -3.0;
const double imMax = +3.0;

for (int x = 0; x < plane.Width; x++)
{
double re = reMin + x * (reMax - reMin) / plane.Width;
for (int y = 0; y < plane.Height; y++)
{
double im = imMax - y * (imMax - imMin) / plane.Height;

var z = new Complex(re, im);
Complex fz = fractal(z);

if (Double.IsInfinity(fz.Re) || Double.IsNaN(fz.Re) ||
Double.IsInfinity(fz.Im) ||
Double.IsNaN(fz.Im))
{
continue;
}

ColorTriplet hsv = ColorMap.ComplexToHsv(fz);

ColorTriplet rgb = ColorMap.HsvToRgb(hsv);
var r = (int)Math.Truncate(255.0 * rgb.X);
var g = (int)Math.Truncate(255.0 * rgb.Y);
var b = (int)Math.Truncate(255.0 * rgb.Z);
Color color = Color.FromArgb(r, g, b);

bitmap.SetPixel(x, y, color);
}
}

plane.Source = Imaging.CreateBitmapSourceFromHBitmap(
bitmap.GetHbitmap(),
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromWidthAndHeight(bitmap.Width, bitmap.Height));
}






Thus, running the code below:




CODE
Plane.MandelbrotFractal().Draw(PlaneCanvas, 20, 1.5);






gives the following result:








For Those Who Want to Go Further



For those who want to go further, you can explore these:




  • Mandelbrot Fractals

  • Julia Fractals

  • Other Newton Fractals

  • Other Fractals






Introduction to Laziness



In this section, we will see how to make a type Lazy.



Lazy evaluation is an evaluation strategy which delays the evaluation of an expression until its value is needed and which also avoids repeated evaluations. The sharing can reduce the running time of certain functions by an exponential factor over other non-strict evaluation strategies, such as call-by-name. Below the benefits of Lazy evaluation.




  • Performance increases by avoiding needless calculations, and error conditions in evaluating compound expressions

  • The ability to construct potentially infinite data structure: We can easily create an infinite set of integers, for example, through a function (see the example on prime numbers in the Sets section)

  • The ability to define control flow (structures) as abstractions instead of primitives



Let's have a look at the code below:




CODE
public class MyLazy<T>
{
#region Fields

private readonly Func<T> _f;
private bool _hasValue;
private T? _value;

#endregion

#region Constructors

public MyLazy(Func<T> f)
{
_f = f;
}

#endregion

#region Operators

//
// Use objects of type MyLazy<T> as objects of type T
// through implicit keyword
//
public static implicit operator T?(MyLazy<T?> lazy)
{
if (!lazy._hasValue)
{
lazy._value = lazy._f();
lazy._hasValue = true;
}

return lazy._value;
}

#endregion
}






MyLazy<T> is a generic class that contains the following fields:




  • _f: A function for lazy evaluation that returns a value of type T

  • _value: A value of type T (frozen value)

  • _hasValue: A boolean that indicates whether the value has been calculated or not



In order to use objects of type MyLazy<T> as objects of type T, the implicit keyword is used. The evaluation is done at type casting time, this operation is called thaw.



Thus, running the code below:




CODE
var myLazyRandom = new MyLazy<double>(GetRandomNumber);
double myRandomX = myLazyRandom;
Console.WriteLine("\n Random with MyLazy<double>: {0}", myRandomX);






where GetRandomNumber returns a random double as follows:




CODE
static double GetRandomNumber() => new Random().NextDouble();






gives the following output:





The .NET Framework 4 also introduced ThreadLocal and LazyInitializer for Lazy evaluation.






Unit Tests



Below are the unit tests for sets of numbers using xUnit.




CODE
using Functional.Core;

namespace Functional.UnitTests;

public class SetUnitTest
{
[Fact]
public void TestEmptySet()
{
Assert.False(Set.Empty<int>()(7));
}

[Fact]
public void TestSetAll()
{
Assert.True(Set.All<int>()(7));
}

[Fact]
public void TestSingleton()
{
Assert.False(Set.Singleton(0)(7));
Assert.True(Set.Singleton(7)(7));
}

[Fact]
public void TestEvenNumbers()
{
Assert.False(Set.Even(99));
Assert.True(Set.Even(998));
}

[Fact]
public void TestOddNumbers()
{
Assert.True(Set.Odd(99));
Assert.False(Set.Odd(998));
}

[Fact]
public void TestMultiplesOfThree()
{
Assert.True(Set.MultipleOfThree(99));
Assert.False(Set.MultipleOfThree(998));
}

[Fact]
public void TestMultiplesOfFive()
{
Assert.True(Set.MultipleOfThree(15));
Assert.False(Set.MultipleOfThree(998));
}

[Fact]
public void TestPrimes()
{
Assert.False(Set.Prime(0));
Assert.True(Set.Prime(2));
Assert.False(Set.Prime(4));
Assert.Equal(104743, Set.Primes(Set.Prime).Skip(10000).First());
}

[Fact]
public void TestUnion()
{
Assert.True(Set.Even.Union(Set.Odd)(7));
}

[Fact]
public void TestIntersection()
{
Predicate<int> multiplesOfThreeAndFive = Set.MultipleOfThree.Intersection(Set.MultipleOfFive);
Assert.True(multiplesOfThreeAndFive(15));
Assert.False(multiplesOfThreeAndFive(10));
}

[Fact]
public void TestCartesianProduct()
{
Func<int, int, bool> cartesianProduct = Set.MultipleOfThree.CartesianProduct(Set.MultipleOfFive);
Assert.True(cartesianProduct(9, 15));
Assert.False(cartesianProduct(10, 15));
}

[Fact]
public void TestComplement()
{
Assert.False(Set.MultipleOfThree.Complement(Set.MultipleOfFive)(15));
Assert.True(Set.MultipleOfThree.Complement(Set.MultipleOfFive)(9));
}

[Fact]
public void TestSymmetricDifferenceWithoutXor()
{
Predicate<int> sdWithoutXor = Set.Prime.SymmetricDifferenceWithoutXor(Set.Even);
Assert.False(sdWithoutXor(2));
Assert.True(sdWithoutXor(4));
Assert.True(sdWithoutXor(7));
}

[Fact]
public void TestSymmetricDifferenceWithXor()
{
Predicate<int> sdWithXor = Set.Prime.SymmetricDifferenceWithXor(Set.Even);
Assert.False(sdWithXor(2));
Assert.True(sdWithXor(4));
Assert.True(sdWithXor(7));
}

[Fact]
public void TestContains()
{
Assert.False(Set.Singleton(0).Contains(7));
Assert.True(Set.Singleton(7).Contains(7));
}

[Fact]
public void TestAdd()
{
Assert.True(Set.Singleton(0).Add(7)(7));
Assert.True(Set.Singleton(1).Add(0)(0));
Assert.False(Set.Singleton(19).Add(0)(7));
}

[Fact]
public void TestRemove()
{
Assert.False(Set.Singleton(0).Remove(0)(7));
Assert.False(Set.Singleton(7).Remove(7)(0));
Assert.False(Set.All<int>().Remove(0)(0));
Assert.True(Set.All<int>().Remove(0)(7));
}
}






Below are unit tests for lazy evaluation.




CODE
using Functional.Core;

namespace Functional.UnitTests;

public class LazyUnitTest
{
static double GetRandomNumber() => new Random().NextDouble();

[Fact]
public void TestMyLazy()
{
var myLazyRandom = new MyLazy<double>(GetRandomNumber);
double myRandomX = myLazyRandom; // implicit cast
Assert.NotNull(myLazyRandom);
Assert.Equal(myRandomX, myLazyRandom);
}
}






After running the unit tests with the following commands:




CODE
cd functional-cs/tests/Functional.UnitTests
dotnet test --verbosity normal /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura






We reach 100% of code coverage. You can generate the coverage report with the following command after running the unit tests:




CODE
dotnet tool install -g dotnet-reportgenerator-globaltool
reportgenerator -reports:"./coverage.cobertura.xml" -targetdir:"coveragereport" -reporttypes:Html






The coverage report is written in ./coveragereport folder.



That's it! I hope you enjoyed reading.

Vollständiger Original-Bericht
Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 0%
🟡 In Evaluierung 0%
🟢 Keine Auswirkung 0%
Spannende Innovation 0%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
1 Quelle
Microsoft Account Passkey not working [Fix]
1 Quelle
September-Patchday-Chaos: Microsoft flickt langsam sein eigenes Update
1 Quelle
Die neue Apple Watch mit Windows Recall?
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Functional Programming in C#

Thematisch verwandte Begriffe: Functional, Programming · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...