15,880,200 members
Articles / Programming Languages / C#

Functional Programming in C#

Rate me:
11 Apr 2024CPOL20 min read 45.9K   536   54   8
Functional Programming in C# through Algebra, Numbers, Euclidean Plane and Fractals
This article discusses Functional Programming in C# through Algebra, Numbers, Euclidean Plane and Fractals. A wide range of topics are covered related to functional programming and set operations. Code examples and explanations are provided to help readers understand the concepts and how to implement them in C#.

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 external 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.

This article will not discuss the basics of functional programming, as you can find numerous resources on this topic on the Internet. 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.

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 Characteristic Function `S'(x)` of the set `S'` is a function which associates either `true` or `false` with each element `x` of `S`.

```S'(x) = true if x is in S'
S'(x) = false if x is not in S'```

Let `S` be the set of books on the table and let `S'` be the set of green books on the table. Let `a` and `b` be two green books, and let `c` and `d` be two red books on the table. Then:

```S'(a) = S'(b) = true
S'(c) = S'(d) = false```

Let `S` be the set of the videos in YouTube and let `S'` be the set of cultural videos in YouTube. Let `a` and `b` be two cultural videos in YouTube, and `c` and `d` be two non-cultural videos in YouTube. Then:

```S'(a) = S'(b) = true
S'(c) = S'(d) = false```

Let `S` be the set of the points in the Euclidean plane and let `S'` be the set of the points in the circle of radius 1 centered at the origin of the Euclidean plane (0, 0) (unit circle). Let `a` and `b` be two points in the unit circle, and let `c` and `d` be two points in a circle of radius 2 centered at the origin of the Euclidean plane. Then:

```S'(a) = S'(b) = true
S'(c) = S'(d) = false```

Thus, any set `S'` can always be represented by its Characteristic Function. A function that takes as argument an element and returns `true` if this element is in `S'`, `false` otherwise. In other words, a set (abstract data type) can be represented through a `Predicate` in C#.

C#
`Predicate<T> set;`

In the next sections, we will see how to represent some fundamental sets in the algebra of sets through C# in a functional way, then we will define generic binary operations on sets. We will then apply these operations on numbers then on subsets of the Euclidean Plane. Sets are abstract data structures, the subsets of numbers and the subsets of the Euclidean plane are the representation of abstract data-structures, and finally the binary operations are the generic logics that works on any representation of the abstract data structures.

Sets

This section introduces the representation of some fundamental sets in the algebra of sets through C#.

Empty Set

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:

```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:

C#
`public static Predicate<T> Empty<T>() => _ => false;`

In algebra of sets, `Empty` is represented as follows:

Thus, running the code below:

C#
```Console.WriteLine("\nEmpty set:");
Console.WriteLine("Is 7 in {{}}? {0}", Empty<int>()(7));```

gives the following results:

Set All

Let `S` be a set and `S'` be the subset of `S` that contains all the elements and `All` its Characteristic function. In algebra of sets, `S'` is the full set that contains all the elements. Therefore, `All` can be defined like this:

`All(x) = true if x is in S`

Thus, the representation of `S'` in C# can be defined as follows:

C#
`public static Predicate<T> All<T>() => _ => true;`

In algebra of sets, `All` is represented as follows:

Thus, running the code below:

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

gives the following results:

Singleton Set

Let `E` be the Singleton set and `Singleton` its Characteristic function. In algebra of sets, `E` also known as unit set, or 1-tuple is a set with exactly one element `e`. Therefore, `Singleton` can be defined as follows:

```Singleton(x) = true if x is e
Singleton(x) = false if x is not e```

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

C#
`public static Predicate<T> Singleton<T>(T e) where T : notnull => x => e.Equals(x);`

Thus, running the code below:

C#
```Console.WriteLine("Is 7 in the singleton {{0}}? {0}", Singleton(0)(7));
Console.WriteLine("Is 7 in the singleton {{7}}? {0}", Singleton(7)(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:

```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:

C#
`Predicate<int> even = i => i % 2 == 0;`

Thus, running the code below:

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

gives the following results:

Odd Numbers

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

```Odd(x) = true if x is not a multiple of 2
Odd(x) = false if x is a multiple of 2```

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

C#
`Predicate<int> odd = i => i % 2 == 1;`

Thus, running the code below:

C#
```Console.WriteLine("Is {0} odd? {1}", 99, odd(99));
Console.WriteLine("Is {0} odd? {1}", 998, odd(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:

```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:

C#
`Predicate<int> multipleOfThree = i => i % 3 == 0;`

Thus, running the code below:

C#
```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:

Multiples of 5

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

```MultipleOfFive(x) = true if x is divisible by 5
MultipleOfFive(x) = false if x is not divisible by 5```

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

C#
`Predicate<int> multipleOfFive = i => i % 5 == 0;`

Thus, running the code below:

C#
```Console.WriteLine("Is {0} a multiple of 5? {1}", 15, multipleOfFive(15));
Console.WriteLine("Is {0} a multiple of 5? {1}", 998, multipleOfFive(998));```

gives the following results:

Prime Numbers

A long time ago, when I was playing with Project Euler problems, I had to resolve the following one:

```By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13,
we can see that the 6th prime is 13.
What is the 10 001st prime number?```

To resolve this problem, I first had to write a fast algorithm that checks whether a given number is prime or not. Once the algorithm was written, I wrote an iterative algorithm that iterates through primes until the 10 001st prime number was found. Nevertheless, is the next iterative algorithm really necessary? You will see.

The algorithm that checks whether a given number is prime or not is the Characteristical function of the primes set.

Let `E` be the set of primes and `Prime` its Characteristic function. In mathematics, a prime is a natural number greater than 1 that has no positive divisors other than 1 and itself. Therefore, `Prime` can be defined as follows:

```Prime(x) = true if x is prime
Prime(x) = false if x is not prime```

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

C#
`Predicate<int> prime = IsPrime;`

where `IsPrime` is a method that checks whether a given number is prime or not.

C#
```static bool IsPrime(int i)
{
if (i == 1) return false;            // 1 is not prime
if (i < 4) return true;              // 2 and 3 are primes
if ((i >> 1) * 2 == i) return false; // multiples of 2 are not prime
if (i < 9) return true;              // 5 and 7 are primes
if (i % 3 == 0) return false;        // multiples of 3 are not primes

// If a divisor less than or equal to sqrt(i) is found,
// then i is not prime
int sqrt = (int)Math.Sqrt(i);
for (int d = 5; d <= sqrt; d += 6)
{
if (i % d == 0) return false;
if (i % (d + 2) == 0) return false;
}

// Otherwise i is prime
return true;
}```

Thus, running the code below to resolve our problem:

C#
```int p = Primes(prime).Skip(10000).First();
Console.WriteLine("The 10 001st prime number is {0}", p);```

where `Primes` is defined below:

C#
```static IEnumerable <int> Primes(Predicate<int> prime)
{
yield return 2;

int p = 3;
while (true)
{
if (prime(p)) yield return p;
p += 2;
}
}```

gives the following results:

Binary Operations

This section presents several fundamental operations for constructing new sets from given sets and for manipulating sets. Below is the Venn diagram in the algebra of sets.

Union

Let `E` and `F` be two sets. The union of `E` and `F`, denoted by `E U F` is the set of all elements which are members of either `E` and `F`.

Let `Union` be the union operation. Thus, the `Union` operation can be implemented as follows in C#:

C#
```public static Predicate<T> Union<T>(this Predicate<T> e, Predicate<T> f)
=> x => e(x) || f(x);```

As you can see, `Union` is an extension function on the Characteristic function of a set. All the operations will be defined as extension functions on the Characteristic function of a set. Thereby, running the code below:

C#
`Console.WriteLine("Is 7 in the union of Even and Odd Integers Set? {0}", Even.Union(Odd)(7));`

gives the following results:

Intersection

Let `E` and `F` be two sets. The intersection of `E` and `F`, denoted by `E n F` is the set of all elements which are members of both `E` and `F`.

Let `Intersection` be the intersection operation. Thus, the `Intersection` operation can be implemented as follows in C#:

C#
```public static Predicate<T> Intersection<T>(this Predicate<T> e, Predicate<T> f)
=> x => e(x) && f(x);```

As you can see, `Intersection` is an extension function on the Characteristic function of a set. Thereby, running the code below:

C#
```Predicate<int> multiplesOfThreeAndFive = multipleOfThree.Intersection(multipleOfFive);
Console.WriteLine("Is 15 a multiple of 3 and 5? {0}", multiplesOfThreeAndFive(15));
Console.WriteLine("Is 10 a multiple of 3 and 5? {0}", multiplesOfThreeAndFive(10));```

gives the following results:

Cartesian Product

Let `E` and `F` be two sets. The cartesian product of `E` and `F`, denoted by `E × F` is the set of all ordered pairs `(e, f)` such that `e` is a member of ` E` and `f` is a member of `F`.

Let `CartesianProduct` be the cartesian product operation. Thus, the `CartesianProduct` operation can be implemented as follows in C#:

C#
```public static Func<T1, T2, bool>
CartesianProduct<T1, T2>(this Predicate<T1> e, Predicate<T2> f) => (x, y)
=> e(x) && f(y);```

As you can see, `CartesianProduct` is an extension function on the Characteristic function of a set. Thereby, running the code below:

C#
```Func<int, int, bool> cartesianProduct = multipleOfThree.CartesianProduct(multipleOfFive);
Console.WriteLine("Is (9, 15) in MultipleOfThree x MultipleOfFive? {0}",
cartesianProduct(9, 15));```

gives the following results:

Complements

Let `E` and `F` be two sets. The relative complement of `F` in `E`, denoted by `E \ F` is the set of all elements which are members of `E` but not members of `F`.

Let `Complement` be the relative complement operation. Thus, the `Complement` operation can be implemented as follows in C#:

C#
```public static Predicate<T> Complement<T>(this Predicate<T> e, Predicate<T> f)
=> x => e(x) && !f(x);```

As you can see, `Complement` is an extension method on the Characteristic function of a set. Thereby, running the code below:

C#
```Console.WriteLine("Is 15 in MultipleOfThree \\ MultipleOfFive set? {0}",
multipleOfThree.Complement(multipleOfFive)(15));
Console.WriteLine("Is 9 in MultipleOfThree \\ MultipleOfFive set? {0}",
multipleOfThree.Complement(multipleOfFive)(9));```

gives the following results:

Symmetric Difference

Let `E` and `F` be two sets. The symmetric difference of `E` and `F`, denoted by `E Δ F` is the set of all elements which are members of either `E` and `F` but not in the intersection of `E` and `F`.

Let `SymmetricDifference` be the symmetric difference operation. Thus, the `SymmetricDifference` operation can be implemented in two ways in C#. A trivial way is to use the union and complement operations as follows:

C#
```public static Predicate<T> SymmetricDifferenceWithoutXor<T>
(this Predicate<T> e, Predicate<T> f)
=> Union(e.Complement(f), f.Complement(e));```

Another way is to use the `XOR` binary operation as follows:

C#
```public static Predicate<T> SymmetricDifferenceWithXor<T>
(this Predicate<T> e, Predicate<T> f)
=> x => e(x) ^ f(x);```

As you can see, `SymmetricDifferenceWithoutXor` and `SymmetricDifferenceWithXor` are extension methods on the Characteristic function of a set. Thereby, running the code below:

C#
```// SymmetricDifference without XOR
Console.WriteLine("\nSymmetricDifference without XOR:");
Predicate<int> sdWithoutXor = prime.SymmetricDifferenceWithoutXor(even);
Console.WriteLine("Is 2 in the symmetric difference of prime and even Sets? {0}",
sdWithoutXor(2));
Console.WriteLine("Is 4 in the symmetric difference of prime and even Sets? {0}",
sdWithoutXor(4));
Console.WriteLine("Is 7 in the symmetric difference of prime and even Sets? {0}",
sdWithoutXor(7));

// SymmetricDifference with XOR
Console.WriteLine("\nSymmetricDifference with XOR:");
Predicate<int> sdWithXor = prime.SymmetricDifferenceWithXor(even);
Console.WriteLine("Is 2 in the symetric difference of prime and even Sets? {0}",
sdWithXor(2));
Console.WriteLine("Is 4 in the symmetric difference of prime and even Sets? {0}",
sdWithXor(4));
Console.WriteLine("Is 7 in the symmetric difference of prime and even Sets? {0}",
sdWithXor(7));```

gives the following results:

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#:

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

Therefore, running the code below:

C#
```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:

Let `Add` be the operation that adds an element to a set. This operation is an extension function on the Characteristic function of a set that takes as parameter an element and adds it to the set.

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

C#
```public static Predicate<T> Add<T>(this Predicate<T> s, T e) where T : notnull
=> x => x.Equals(e) || s(x);```

Therefore, running the code below:

C#
```Console.WriteLine("Is 7 in {{0, 7}}? {0}", Singleton(0).Add(7)(7));
Console.WriteLine("Is 0 in {{1, 0}}? {0}", Singleton(1).Add(0)(0));
Console.WriteLine("Is 7 in {{19, 0}}? {0}", Singleton(19).Add(0)(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#:

C#
```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:

C#
```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:

For Those Who Want to Go Further

You can see how easily we can do some algebra of sets in C# through functional programming. In the previous sections was shown the most fundamental definitions. But, if you want to go further, you can think about:

• Relations over sets
• Abstract algebra, such as monoids, groups, fields, rings, K-vectorial spaces and so on
• Inclusion-exclusion principle
• Dual vector space
• Theorems and Corollaries

Euclidean Plane

In the previous section, the fundamental concepts on sets were implemented in C#. In this section, we will practice the concepts implemented on the set of plane points (Euclidean plane).

Drawing a Disk

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:

C#
```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 `c` is the Euclidean distance, `a²` is `(point1.X - point2.X)²` and `b²` is `(point1.Y - point2.Y)²`.

Let `Disk` be the Characteristic function of a closed disk. In algebra of sets, the definition of a closed disk in the reals set is as follows:

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

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

C#
```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`.

Below the implementation of the method.

C#
```public static void Draw(this Predicate<Point> set, Image plane)
{
var bitmap = new Bitmap((int)plane.Width, (int)plane.Height);

//
// Graph drawing
//
double semiWidth = plane.Width / 2;
double semiHeight = plane.Height / 2;

double xMin = -semiWidth;
double xMax = +semiWidth;
double yMin = -semiHeight;
double yMax = +semiHeight;

for (int x = 0; x < bitmap.Height; x++)
{
double xp = xMin + x * (xMax - xMin) / plane.Width;

for (int y = 0; y < bitmap.Width; y++)
{
double yp = yMax - y * (yMax - yMin) / plane.Height;

if (set(new Point(xp, yp)))
{
bitmap.SetPixel(x, y, Color.Black);
}
}
}

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

In the `Draw` method, a `bitmap` having the same width and same height as the Euclidean plane container is created. Then each point in pixels `(x,y)` of the `bitmap` is replaced by a black point if it belongs to the `set`. `xMin`, `xMax`, `yMin` and `yMax` are the bounding values illustrated in the figure of the Euclidean plane above.

As you can see, `Draw` is an extension function on the Characteristic function of a set of points. Therefore, running the code below:

C#
`Plane.Disk(new Point(0, 0), 20).Draw(PlaneCanvas);`

gives the following result:

Drawing Horizontal and Vertical Half-Planes

A horizontal or a vertical half-plane is either of the two subsets into which a plane divides the Euclidean space. A horizontal half-plane is either of the two subsets into which a plane divides the Euclidean space through a line perpendicular with the Y axis like in the figure above. A vertical half-plane is either of the two subsets into which a plane divides the Euclidean space through a line perpendicular with the X axis.

In this section, we will set up the Characteristic functions of the horizontal and vertical half-planes, draw them in WPF and see what we can do if we combine them with the disk subset.

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

C#
```public static Predicate<Point> HorizontalHalfPlane(double y, bool lowerThan)
=> p => lowerThan ? p.Y <= y : p.Y >= y;```

Thus, running the code below:

C#
`Plane.HorizontalHalfPlane(0, true).Draw(PlaneCanvas);`

gives the following result:

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

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

Thus, running the code below:

C#
`Plane.VerticalHalfPlane(0, false).Draw(PlaneCanvas);`

gives the following result:

In the first section of the article, we set up basic binary operations on sets. Thus, by combining the intersection of a `disk` and a `half-plane` for example, we can draw the half-disk subset.

Therefore, running the sample below:

C#
`Plane.VerticalHalfPlane(0, false).Intersection(Plane.Disk(new Point(0, 0), 20)).Draw(PlaneCanvas);`

gives the following result:

Functions

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

Translate

Let `Translate` be the function that translates a point in the plane. In Euclidean geometry, `Translate` is a function that moves a given point a constant distance in a specified direction. Thus the implementation in C# is as follows:

C#
```private static Func<Point, Point> Translate(double deltax, double deltay)
=> p => new Point(p.X + deltax, p.Y + deltay);```

where `(deltax, deltay)` is the constant vector of the translation.

Let `TranslateSet` be the function that translates a set in the plane. This function is simply implemented as follows in C#:

C#
```public static Predicate<Point> TranslateSet
(this Predicate<Point> set, double deltax, double deltay)
=> x => set(Translate(-deltax, -deltay)(x));```

`TranslateSet` is an extension function on a set. It takes as parameters `deltax` which is the delta distance in the first Euclidean dimension and `deltay` which is the delta distance in the second Euclidean dimension. If a point P (x, y) is translated in a set S, then its coordinates will change to (x', y') = (x + delatx, y + deltay). Thus, the point (x' - delatx, y' - deltay) will always belong to the set S. In set algebra, `TranslateSet` is called isomorph, in other words, the set of all translations forms the translation group T, which is isomorphic to the space itself. This explains the main logic of the function.

Thus, running the code below in our WPF application:

C#
`TranslateDiskAnimation();`

where `TranslateDiskAnimation` is described below:

C#
```private const double Delta = 50;
private double _diskDeltay;
private readonly Predicate<Point> _disk = Plane.Disk(new Point(0, -170), 80);

private void TranslateDiskAnimation()
{
DispatcherTimer diskTimer = new DispatcherTimer
{ Interval = new TimeSpan(0, 0, 0, 1, 0) };
diskTimer.Tick += TranslateTimer_Tick;
diskTimer.Start();
}

private void TranslateTimer_Tick(object? sender, EventArgs e)
{
_diskDeltay = _diskDeltay <= plan.Height ? _diskDeltay + Delta : Delta;
Predicate<Point> translatedDisk = _diskDeltay <= plan.Height ?
_disk.TranslateSet(0, _diskDeltay) : _disk;
translatedDisk.Draw(PlaneCanvas);
}```

gives the following result:

Homothety

Let `Scale` be the function that sends any point M to another point N such that the segment SN is on the same line as SM, but scaled by a factor λ. In algebra of sets, `Scale` is formulated as follows:

Thus the implementation in C# is as follows:

C#
```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#:

C#
```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:

C#
`ScaleDiskAnimation();`

where `ScaleDiskAnimation` is described below:

C#
```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:

Rotate

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

where (x', y') are the co-ordinates of the point after rotation, and the formula for x' and y' is as follows:

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

Below the demonstration:

Thus the implementation in C# is as follows:

C#
```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#.

C#
```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:

C#
`RotateHalfPlaneAnimation();`

where `RotateHalfPlaneAnimation` is described below:

C#
```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:

For Those Who Want to Go Further

Very simple, isn't it? For those who want to go further, you can explore these:

• Ellipse
• Three-dimensional Euclidean space
• Ellipsoid
• Paraboloid
• Hyperboloid
• Spherical harmonics
• Superellipsoid
• Haumea
• Homoeoid
• Focaloid

Fractals

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:

`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:

A Mandelbrot set is illustrated above.

Fractals (abstract data type) can always be represented as follows in C#:

C#
`Func<Complex, Complex> fractal;`

Complex Numbers and Drawing

In order to be able to draw fractals, I needed to manipulate Complex numbers. Thus, I've used `Meta.numerics` library. I also needed an utility to draw complex numbers in a `Bitmap`, thus I used `ColorMap` and `ClorTriplet` classes that are available in this CodeProject article.

Mandelbrot Fractal

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

C#
`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#.

C#
```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:

C#
`Plane.MandelbrotFractal().Draw(PlaneCanvas, 20, 1.5);`

gives the following result:

Newton Fractal

I've also created a Newton Fractal (abstract data type representation) `P(z) = z^3 - 2*z + 2` that is available below:

C#
`public static Func<Complex, Complex> NewtonFractal() => z => z * z * z - 2 * z + 2;`

Thus, running the code below:

C#
`Plane.NewtonFractal().Draw(PlaneCanvas);`

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:

C#
```public class MyLazy<T>
{
#region Fields

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:

C#
```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:

C#
`static double GetRandomNumber() => new Random().NextDouble();`

gives the following output:

The .NET Framework 4 introduced a class `System.Lazy<T>` for lazy evaluation. This class returns the value through the property `Value`. Running the code below:

C#
```var lazyRandom = new Lazy<double>(GetRandomNumber);
double randomX = lazyRandom;```

gives a compilation error because the type `Lazy<T>` is different from the type `double`.

To work with the value of the class `System.Lazy<T>`, the property `Value` has to be used as follows:

C#
```var lazyRandom = new Lazy<double>(GetRandomNumber);
double randomX = lazyRandom.Value;
Console.WriteLine("\n Random with System.Lazy<double>.Value: {0}", randomX);```

which gives the following output:

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

Running the Source Code

To run the source code, you will need Visual Studio 2022 and .NET 7.0 SDK.

Below are the projects available in the solution:

• `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.

That's it! I hope you enjoyed reading.

History

• 19th October 2023:
• Initial release
• 11th April 2024:
• Bump System.Drawing.Common from 7.0.0 to 8.0.4

Written By
Engineer
Morocco
I build innovative and scalable solutions for digital media. With several years of software engineering experience, I have a strong background in web, mobile and desktop development, as well as media asset management and digital asset management systems.

My strength lies in the development of innovative solutions and the ability to adapt them to different industries looking to streamline or automate their work process or data management.

I am passionate about learning new technologies and frameworks and applying them to solve complex and challenging problems. I am proficient in working with Node.js, React, React Native, TypeScript, C# and .NET among other languages and tools. My ultimate aim is to deliver high-quality software products that meet the requirements and expectations of our customers.

Open-source projects:

- Wexflow: .NET Workflow Engine and Automation Platform
- BookCars: Car Rental Platform with Mobile App
- Movin' In: Rental Property Management Platform with Mobile App
- Wexstream: Video Conferencing Platform
- wexCommerce: eCommerce Platform on Next.js

If you'd like to discuss any sort of opportunity, feel free to contact me through GitHub or LinkedIn.

 First Prev Next
 My vote of 5 Daniel Myshkin22-Nov-23 4:03 Daniel Myshkin 22-Nov-23 4:03
 Criteria for a good function Member-24326967-Nov-23 7:41 Member-2432696 7-Nov-23 7:41
 Functional Programming in C# Member 78935317-Nov-23 5:23 Member 7893531 7-Nov-23 5:23
 What a clever idea! Master DJon31-Oct-23 11:48 Master DJon 31-Oct-23 11:48
 You are having fun! Victor Vogelpoel30-Oct-23 3:55 Victor Vogelpoel 30-Oct-23 3:55
 How about recursion? Per Øyvind30-Oct-23 3:04 Per Øyvind 30-Oct-23 3:04
 Well written article! DaveBlack28-Oct-23 10:02 DaveBlack 28-Oct-23 10:02
 My vote of 5 Ștefan-Mihai MOGA19-Oct-23 2:31 Ștefan-Mihai MOGA 19-Oct-23 2:31
 Last Visit: 31-Dec-99 18:00     Last Update: 17-Apr-24 7:49 Refresh 1