Showing posts with label Functional programming. Show all posts
Showing posts with label Functional programming. Show all posts

Monday, 15 July 2024

Caching pure functions using Memoize in C#

This article will present a technique for caching pure functions in C# using Memoize technique. This is a programmatic caching of pure method or function where we have a method that always returns the same result or equivalent result given an input. This adds scalability, maybe the method takes long time to process and we want to avoid using resources and provide a quicker answer. If your method has side effects or does not yield the same or equivalent result (cosmetic changes ignored) given a set of parameter(s), it should not be memoized. But if it does, here is how you can do this. Note that memoize is a general technique used in functional programming and is used in many languages such as Javascript, for example in the Underscore.Js lib. First off, let's define some POCOs to test the memoize function out. We will use a small sample set of movies and their actors and additional information from the fabulous year 1997.

MovieStore.cs


public class MovieStore {
    public string GetActorsByMovieTitle(string movieTitle)
    {
        Console.WriteLine($"Retrieving actors for movie with title {movieTitle} at: {DateTime.Now}");
        List<Movie> movies1997 = System.Text.Json.JsonSerializer.Deserialize<List<Movie>>(movies1997json);
        string actors = string.Join(",", movies1997
        	.FirstOrDefault(m => m.name?.ToLower() == movieTitle?.ToLower())?.actors.ToArray());
        return actors;
    }   
    
    string movies1997json = """
[
{
  "name": "The Lost World: Jurassic Park",
  "year": 1997,
  "runtime": 129,
  "categories": [
    "adventure",
    "action",
    "sci-fi"
  ],
  "releasedate": "1997-05-23",
  "director": "Steven Spielberg",
  "writer": [
    "Michael Crichton",
    "David Koepp"
  ],
  "actors": [
    "Jeff Goldblum",
    "Julianne Moore",
    "Pete Postlethwaite"
  ],
  "storyline": "Four years after the failure of Jurassic Park on Isla Nublar, John Hammond reveals to Ian Malcolm that there was another island (\"Site B\") on which dinosaurs were bred before being transported to Isla Nublar. Left alone since the disaster, the dinosaurs have flourished, and Hammond is anxious that the world see them in their \"natural\" environment before they are exploited."
},
{
  "name": "The Fifth Element",
  "year": 1997,
  "runtime": 127,
  "categories": [
    "action",
    "adventure",
    "sci-fi"
  ],
  "releasedate": "1997-05-09",
  "director": "Luc Besson",
  "writer": [
    "Luc Besson",
    "Robert Mark Kamen"
  ],
  "actors": [
    "Bruce Willis",
    "Milla Jovovich",
    "Gary Oldman",
    "Chris Tucker",
    "Ian Holm",
    "Luke Perry",
    "Brion James",
    "Tommy Lister",
    "Lee Evans",
    "Charlie Creed-Miles",
    "John Neville",
    "John Bluthal",
    "Mathieu Kassovitz",
    "Christpher Fairbank"
  ],
  "storyline": "In the colorful future, a cab driver unwittingly becomes the central figure in the search for a legendary cosmic weapon to keep Evil and Mr. Zorg at bay."
} ,
{
  "name": "Starship Troopers",
  "year": 1997,
  "runtime": 129,
  "categories": [
    "action",
    "adventure",
    "sci-fi",
    "thriller"
  ],
  "releasedate": "1997-11-07",
  "director": "Paul Verhoeven",
  "writer": [
    "Edward Neumeier",
    "Robert A. Heinlein"
  ],
  "actors": [
    "Casper Van Dien",
    "Dina Meyer",
    "Denise Richards",
    "Jake Busey",
    "Neil Patrick Harris",
    "Clancy Brown",
    "Seth Gilliam",
    "Patrick Muldoon",
    "Michael Ironside"
  ],
  "storyline": "In the distant future, the Earth is at war with a race of giant alien insects. Little is known about the Bugs except that they are intent on the eradication of all human life. But there was a time before the war... A Mobile Infantry travels to distant alien planets to take the war to the Bugs. They are a ruthless enemy with only one mission: Survival of their species no matter what the cost..."
}
]
""";
}




Movie.cs


public class Movie
{
    public string name { get; set; }
    public int year { get; set; }
    public int runtime { get; set; }
    public List<string> categories { get; set; }
    public string releasedate { get; set; }
    public string director { get; set; }
    public List<string> writer { get; set; }
    public List<string> actors { get; set; }
    public string storyline { get; set; }
}


Let's suppose the method GetActorsByMovieTitle is called many times or takes a lot of time to calculate. We want to cache it, to memoize it. It will be cached in a simple manner using memoize. This will short term cache the results, if we would like to persist the memoized results for long duration, we would use some other caching service such as database or Redis cache. The caching will function in sequential calls inside the same scope, it could be scoped as a singleton and long term cached inside memory for example. So here is how we can do the memoization shown below.

FunctionalExtensions.cs


public static Func<T1, TOut> Memoize<T1, TOut>(this Func<T1, TOut> @this, Func<T1, string> keyGenerator)
	{
		var dict = new Dictionary<string, TOut>();
		return x =>
		{
			string key = keyGenerator(x);
			if (!dict.ContainsKey(key))
			{
				dict.Add(key, @this(x));
			}
			return dict[key];
		};
	}
	public static Func<T1, T2, TOut> Memoize<T1, T2, TOut>(this Func<T1, T2, TOut> @this, Func<T1, T2, string> keyGenerator)
	{
		var dict = new Dictionary<string, TOut>();
		return (x,y) =>
		{
			string key = keyGenerator(x,y);
			if (!dict.ContainsKey(key))
			{
				dict.Add(key, @this(x,y));
			}
			return dict[key];
		};
	}
	public static Func<T1, T2, T3, TOut> Memoize<T1, T2, T3, TOut>(this Func<T1, T2, T3, TOut> @this, Func<T1, T2, T3, string> keyGenerator)
	{
		var dict = new Dictionary<string, TOut>();
		return (x, y, z) =>
		{
			string key = keyGenerator(x, y,z);
			if (!dict.ContainsKey(key))
			{
				dict.Add(key, @this(x, y, z));
			}
			return dict[key];
		};
	}
	public static Func<T1, T2, T3, T4, TOut> Memoize<T1, T2, T3, T4, TOut>(this Func<T1, T2, T3, T4, TOut> @this, Func<T1, T2, T3, T4, string> keyGenerator)
	{
		var dict = new Dictionary<string, TOut>();
		return (x, y, z, w) =>
		{
			string key = keyGenerator(x, y, z, w);
			if (!dict.ContainsKey(key))
			{
				dict.Add(key, @this(x, y, z, w));
			}
			return dict[key];
		};
	}


As we see above, we use a dictionary inside the memoize overloads and the way generics works, a dictionary will live inside each overloaded method accepting a different count of generic type parameters. We also provide a keyGenerator method that must be supplied to specify how we build up a unique key that we decide how we shall key each results from the given set of parameter(s). Note that we return here a function result, that is a func, that returns TOut and accepts the specified parameters in each overload. T1 or T1,T2 or T1,T2,T3 or T1,T2,T3,T4 and so on. Expanding the methods above to for example 16 parameters would be fairly easy, the code above shows how we can add support for more and more parameters. I believe you should avoid methods with more than 7 parameters,
but the code above should be clear. We return a func and we also accept also a func which returns TOut and same amount of parameters of same types T1,.. in each overload. Okay, next up an example how we can use this memoize function in the main method.

Program.cs


void Main()
{
    var movieStore = new MovieStore();
    
    //string actors = movieStore.GetActorsByMovieTitle("Starship troopers");
    //actors.Dump("Starship Troopers - Actors");
    //
    //Demo of memoized function
    
    var GetActorsByMovieTitle = ((string movieTitle) => movieStore.GetActorsByMovieTitle(movieTitle));
    var GetActorsByMovieTitleM = GetActorsByMovieTitle.Memoize(x => x);
    
    var starShipTroopersActors1 = GetActorsByMovieTitleM("Starship troopers");
    starShipTroopersActors1.Dump("Starship troopers - Call to method #1 time");
    var starShipTroopersActors2 = GetActorsByMovieTitleM("Starship troopers");
    starShipTroopersActors2.Dump("Starship troopers - Call to method #2 time");
    var starShipTroopersActors3 = GetActorsByMovieTitleM("Starship troopers");
    starShipTroopersActors3.Dump("Starship troopers - Call to method #3 time");
}


Note that in the test case above we send in one parameter T1 of type string, which is a movie title and we declare a func variable first using a lambda. We have to do the memoization in two declarations here and we use the convention that we suffix the memoized function with 'M' for 'Memoize'

Program.cs


void Main()
{
    var movieStore = new MovieStore();    
    var GetActorsByMovieTitle = ((string movieTitle) => movieStore.GetActorsByMovieTitle(movieTitle));
    var GetActorsByMovieTitleM = GetActorsByMovieTitle.Memoize(x => x);

The code has added a Console.WriteLine in the method which is memoized to check how many times the method is actually called or the cached result is returned instead. A run in Linqpad 7 is shown in screenshot below, showing that the output is cached correct. Note that if we wanted a thread implementation, we could instead use ConcurrentDictionary for example. The following methods show how we can do this. We exchanged Dictionary with ConcurrentDictionary and exchanged Add with TryAdd method of ConcurrentDictionary.

Program.cs


	public static Func<T1, TOut> MemoizeV2<T1, TOut>(this Func<T1, TOut> @this, Func<T1, string> keyGenerator)
	{
		var dict = new ConcurrentDictionary<string, TOut>();
		return x =>
		{
			string key = keyGenerator(x);
			if (!dict.ContainsKey(key))
			{
				dict.TryAdd(key, @this(x));
			}
			return dict[key];
		};
	}
	public static Func<T1, T2, TOut> MemoizeV2<T1, T2, TOut>(this Func<T1, T2, TOut> @this, Func<T1, T2, string> keyGenerator)
	{
		var dict = new ConcurrentDictionary<string, TOut>();
		return (x, y) =>
		{
			string key = keyGenerator(x, y);
			if (!dict.ContainsKey(key))
			{
				dict.TryAdd(key, @this(x, y));
			}
			return dict[key];
		};
	}
	public static Func<T1, T2, T3, TOut> MemoizeV2<T1, T2, T3, TOut>(this Func<T1, T2, T3, TOut> @this, Func<T1, T2, T3, string> keyGenerator)
	{
		var dict = new ConcurrentDictionary<string, TOut>();
		return (x, y, z) =>
		{
			string key = keyGenerator(x, y, z);
			if (!dict.ContainsKey(key))
			{
				dict.TryAdd(key, @this(x, y, z));
			}
			return dict[key];
		};
	}
	public static Func<T1, T2, T3, T4, TOut> MemoizeV2<T1, T2, T3, T4, TOut>(this Func<T1, T2, T3, T4, TOut> @this, Func<T1, T2, T3, T4, string> keyGenerator)
	{
		var dict = new ConcurrentDictionary<string, TOut>();
		return (x, y, z, w) =>
		{
			string key = keyGenerator(x, y, z, w);
			if (!dict.ContainsKey(key))
			{
				dict.TryAdd(key, @this(x, y, z, w));
			}
			return dict[key];
		};
	}


Hopefully, memoize or the process of memoization should be clearer now. It is a call based caching technique used preferably for pure functions / methods that has the same or equivalent result given a set of input parameter(s) and we memoize the function / method and cache the results. When used inside e.g. a singleton, we can cache longer time in memory and achieve performance boosts. You could do the same of course using a static variable, but the memoize technique is more generic purpose and is a pattern that is used in many programming languages. F# usually got way better support for functional programming than C#, but actually lacks a built in memoization functionality. Other languages do support memoization built in, such as in Python and LISP. The following screen shot shows a run of memoization above, I used ConcurrentDictionary when I tested.

Tuesday, 2 July 2024

Maybe Monad in C# - Guarding against nulls

This article will look more at the Maybe monad in C#. It is used to guard against nulls and is one of the most known monads in functional programming. The Maybe monad is also called Option or Optional many places. The screenshot below shows the allowed state transitions.

First off, records will be used since they support immutability out of the box.

Maybe.cs


public abstract record Maybe<T>();
public record Nothing<T> : Maybe<T>;
public record UnhandledNothing<T> : Nothing<T>;
public record Something<T>(T Value) : Maybe<T>;
public record Error<T>(Exception CapturedError) : Maybe<T>;
public record UnhandledError<T>(Exception CapturedError) : Error<T>(CapturedError);


As we see, the base record Maybe of T is abstract and can be one of several subtypes. Nothing means there are no value contained inside the 'container' or monad. Something of T means a value is inside the 'container'. This value can be null, but the container wrapping this value is not null, hence by sticking to monads such as Maybe we avoid null issues for the code that lives outside using the container, accessing the container. Maybe container here is no magic bullet, but it will make it easier to avoid null issues in your code in the parts where it is used. Let's next look at extension methods for the Maybe types defined in the records above.

MaybeExtensions.cs


public static class MaybeExtensions
{

	/// <summary>ToMayBe operates as a Return function in functional programming, lifting a normal value into a monadic value</summary>
	public static Maybe<T> ToMaybe<T>(this T @this)
	{		
		if (!EqualityComparer<T>.Default.Equals(@this, default))
		{
			return new Something<T>(@this);
		}
		else if (@this != null && Nullable.GetUnderlyingType(@this.GetType()) == null && @this.GetType().IsPrimitive){
			//primitive types that are not nullable and has got a default value are to be considered to have contents and have Something<T>, for example int value 0 or bool value false
			return new Something<T>(@this);
		}		
		return new Nothing<T>();
	}
	
	/// <summary>TryGetValue is similar to Reduce method in functional programming, but signal a boolean flag if the retrieval of value was successful</summary>
	public static bool TryGetValue<T>(this Maybe<T> @this, out T value){
	 	value = @this switch {
			Something<T> s => s.Value,
			_ => default(T)			
		};
		return @this is Something<T>;
	}
	
    //<summary>Call method Bind first to get correct behavior;/summary>
	public static Maybe<T> OnSomething<T>(this Maybe<T> @this, Action<T> actionOnSomething){
		if (@this is Something<T> s){
			actionOnSomething(s.Value);
		}		
		return @this;
	}
	
    //<summary>Call method Bind first to get correct behavior;/summary>
	public static Maybe<T> OnNothing<T>(this Maybe<T> @this, Action actionOnNothing){
		if (@this is UnhandledNothing<T>){
			actionOnNothing();
			return new Nothing<T>(); //switch from UnhandledNothing<T> to Nothing<T>
		}
		return @this;
	}
	
    //<summary>Call method Bind first to get correct behavior;/summary>
	public static Maybe<T> OnError<T>(this Maybe<T> @this, Action<Exception> actionOnError){
		if (@this is UnhandledError<T> e){
			actionOnError(e.CapturedError);
			return new Error<T>(e.CapturedError); //switch from UnhandledError<T> to Error<T>
		}
		return @this;
	}
		
	/// <summary>Bind is similar to Map in functional programming, it applies a function to update and allow switching from TIn to TOut data types, possibly different types</summary>
	public static Maybe<TOut> Bind<TIn, TOut>(this Maybe<TIn> @this, Func<TIn, TOut> f){
		try
		{
			Maybe<TOut> updatedMaybe = @this switch {
			    null => new Error<TOut>(new Exception("Object input is null")),
				Something<TIn> s when !EqualityComparer<TIn>.Default.Equals(s.Value, default) => new Something<TOut>(f(s.Value)),
				Something<TIn> s when @this.GetType().GetGenericArguments().First().IsPrimitive && Nullable.GetUnderlyingType(@this.GetType()) == null => new Something<TOut>(f(s.Value)),
				Something<TIn> _ => new UnhandledNothing<TOut>(),
				UnhandledNothing<TIn> _ => new UnhandledNothing<TOut>(),
				Nothing<TIn> _ => new Nothing<TOut>(),
				UnhandledError<TIn> u => new UnhandledError<TOut>(u.CapturedError),
				Error<TIn> e => new Error<TOut>(e.CapturedError),
				_ => new Error<TOut>(new Exception($"Got a subtype of Maybe<T>, which is not supported: {@this?.GetType().Name}"))				
			};
			return updatedMaybe;			
		}
		catch (Exception ex)
		{			
			return new UnhandledError<TOut>(ex);
		}		
	}
		
}


The extension methods above handle the basics for the Maybe of T monad.
  • We transform from a value of T to the Maybe of T using the method ToMaybe, this method is called Return many places. I think the name ToMaybe is more intuitive for more developers in C#.
  • The method TryGetValue is called Reduce many places and extracts the value of Maybe of T if it is available and returns a boolean value if the Maybe of T actually contains a value. If Maybe of T is not the type Something of T it does not hold a value, so knowing this is useful after retrieving the value.
  • The method Bind is sometimes called Map and allows updates of the value inside the Maybe of T and also perform transitions of sub types of Maybe of T and uses pattern matching in C#. Bind both maps and also performs the overall flow of state via controlling the sub type of Maybe of T as shown in the pattern specified inside Bind
  • The methods OnError, OnNothing, OnSomething are callbacks to do logic when retrieving values of these types that inherit from Maybe of T. Make sure you call the method Bind first
If you know more methods a Maybe of T monad should support, please let me know. A more detailed example of a Maybe of T monad can be seen in this implementation, note that it is called Option of T instead.

https://github.com/nlkl/Optional/blob/master/src/Optional/Option_Maybe.cs

The benefit with the code in this article is that it is shorter and that it uses records in C#. Since it is shorter, it should be easier to adapt and adjust to the needs. Demo code is next. Consider this record:

Car.cs


public record Car(string Model, string Make, bool? IsFourWheelDrive = null, string? Color = null);




Program.cs


void Main()
{
	var something = new Something<string>("hullo");
	something = something with { Value = null };
	
	var somethingnull = EqualityComparer<string>.Default.Equals(something.Value, default);
	
	int? nullableNumber = 1;
	Maybe<int?> maybe = nullableNumber.ToMaybe();

	var volvo = new Car("240 GL", "Volvo");

	bool isValueRetrieved = volvo.ToMaybe()
		.Bind(car => car with { IsFourWheelDrive = false })
		.Bind(car => car with { Color = "Blue" })
		.TryGetValue(out Car updatedVolvo);

	new { updatedVolvo, isValueRetrieved }.Dump("Updated Volvo");
	
	Maybe<string> noCar = new Something<string>(null)
							.Bind(x => x)
							.OnNothing(() => Console.WriteLine("The Car is nothing (null)!"));
	noCar.Dump("No car");
		
	maybe.Dump("Maybe");
	
	something.Dump();
	
}



Output from Linqpad shows the result from running the demo code. Note that since a record Car was used in the demo code, inside the Bind calls it was necessary to use the 'with' to mutate the record and create a new record
with the necessary adjustments. Also, it is important to call Bind before handlers OnNothing, OnError and OnSomething to work properly in the code, since the transition rules inside Bind should run first to check the correct subtype of Maybe of T. Many implementations of Option of T or Maybe of T that is, also implement operators for equality comparison of the value inside the Maybe of T if there is a defined value there (i.e. Something of T). The mentioned example on Github goes in detail on this and adds several methods for equality comparisons. Also, there are examples of support async methods such as BindAsync in Maybe of T implementations out there. Many of the building blocks of functional programming in C# are not standardized or built into the framework, so working out these building blocks yourself to tailour your source code needs is probably a good solution, if not going for libraries such as LanguageExt.

https://github.com/louthy/language-ext

Finally, notice that in the screenshot below, we have a Value of null for the variable something in the demo code. To get the proper sub type of Maybe of T, we should also call the Bind method. If we instead of :

  something.Dump();

Do this:

  something.Bind(x => x).Dump();

We get the correct subtype of Maybe of T, UnhandledNothing of T.

And if we also handle the UnhandledNothing of T, we get Nothing of T. 

something.Bind(x => x).OnNothing(() => Console.WriteLine("something is null")).Dump();

Sunday, 30 June 2024

Fork combinator revisited - supporting multiple part functions in C#

This article shows an example of a Fork combinator or 'monad' that will allow you to specify a join function that operates on all the part results and allow you to specify multiple part functions to be operated in sequence. First off, we define a simple map monad to map a value to another value of possibly other type. Then we define the fork combinator. The code below is very simple and short, it uses LINQ functionality to combine the results via the Select method, Linq is also functional so this is how we build up functional monads in C#, using Linq and Func and generics (and pattern matching and more).

Combinators.cs


public static class Combinators {
	
	public static TOut Map<TIn, TOut>(this TIn @this, Func<TIn, TOut> f) => f(@this);
	
	public static TOut Fork<TIn, TMiddle, TOut>(this TIn @this, Func<IEnumerable<TMiddle>, TOut> joinFunc,
		params Func<TIn, TMiddle>[] partFuncs) => partFuncs.Select(pf => pf(@this)).Map(joinFunc);
	
}


Let's look at a simple demo how to use this

Program.cs


public static class Program {
	
	string hello = "hhhhhheeeeeeeelllllllllllooooo";
	
	int sumOfLettersToLookFor = hello.Fork(results => (int)results.Sum(), 
				x => (double)x.Count(l => l == 'h'),
				x => (double) x.Count(l => l == 'e'),
				x => (double) x.Count(l => l == 'l'),
				x => (double) x.Count(l => l == 'o'));
	
	sumOfLettersToLookFor.Dump();
	
}


Functional programming has many of these monads that are very short and allows you to do combinations that would be lengthy and stateful in the procedural / object oriented way but elegant and short in the functional world. Finally a screenshot from Linqpad 7 showing the code above works : (A reference to Jerry Seinfeld to the right for those who know Seinfeld episodes)

Wednesday, 26 June 2024

Functional programming - Guarding against nulls with the Option monad

Monads are "elementary individual substances". We can call them "building blocks" in Functional Programming (FP) and FP is built upon such building blocks to compose more complex logic. This article sums up using the

Option

monad, which is described many places on the net and is wellknown. This article is just a walkthrough of this monad, which creates a wrapper for a value that will aid against guarding against nulls. We will effectively abstract away null, and using extension methods we will allow setting up a processing chain where nulls are wrapped inside a value inside the Option objects. First off, define a generic class for this monad and in this case we will consider reference types or classes (this includes strings). Also, equality operators can be added to make it easier to do equality checks. The class will be called Option and we will define two methods called None and Some. The field called _content of type T will be returned inside a Option wrapper instance and None will only return Option object where _content is null.
  • None() signals that the payload or _content is null. None method returns an instance of Option of T where the wrapped value is null.
  • Some() signals that the payload or _content> is not null. some method returns an instance of Option of T where the wrapped value is not null.
  • Both the None() and Some() are of type Option<T> and can be used in a chained expression.
Some concepts of what the Option should support :
  • A map method that allows transforming from T to TResult (both can be same type) along the chained expressions
  • A reduce method that allows retrieving the value inside the Option object that is wrapped
  • Extension methods for going from an object to an Option wrapper of the object
  • Predicate based filter methods for peeling away Option objects where the wrapped object which satisfy the filter can be filtered



public class Option<T> : IEquatable<Option<T>> where T : class {
	
	private T? _content;
	
	private Option(){}

	public static Option<T> None() => new();
	public static Option<T> Some(T obj) => new Option<T> { _content = obj };

	public override bool Equals(object? obj)
	{
		return this.Equals(obj as Option<T>);
	}
	
	public Option<T> Where(Func<T, bool> predicate) => 
		_content is not null && predicate(_content) ? this : Option<T>.None();

	public Option<T> WhereNot(Func<T, bool> predicate) =>
		_content is not null && !predicate(_content) ? this : Option<T>.None();

	public bool Equals(Option<T>? other) => other is null ? false :
		_content?.Equals(other._content) ?? false;
		
	public static bool operator ==(Option<T>? a, Option<T>? b) => 
		a is null ? b is null : a.Equals(b);
		
	public static bool operator !=(Option<T>? a, Option<T>? b) => !(a == b);
		
	public override int GetHashCode()
	{
		return _content?.GetHashCode() ?? 0;
	}

	public Option<TResult> MapOptional<TResult>(Func<T, Option<TResult>> map) where TResult : class =>
		_content is not null ? map(_content) : Option<TResult>.None();

	public Option<TResult> Map<TResult>(Func<T, TResult> map) where TResult : class =>
		new Option<TResult>() { _content = _content is not null ? map(_content) : null };
	
    public T Reduce(T orElse) => _content ?? orElse;
	
	public T Reduce(Func<T> orElse) => _content ?? orElse();
	
} 


We also add some extension methods to help using the monad Option above containing the Some and None methods :

 
 
 public static class OptionExtensions {
	
	public static Option<T> ToOption<T>(this T? obj) where T : class => obj is not null ? Option<T>.Some(obj) : Option<T>.None();

	public static Option<T> Where<T>(this T? obj, Func<T, bool> predicate) where T : class => obj is not null && predicate(obj) ? Option<T>.Some(obj) : Option<T>.None();
	
	public static Option<T> WhereNot<T>(this T? obj, Func<T, bool> predicate) where T : class => obj is not null && !predicate(obj) ? Option<T>.Some(obj) : Option<T>.None();

}

 
Let's also add a ForEach extension method for easier usage in chained expressions of ienumerable collections.
 
 
 public static class IEnumerableExtensions {
	
	public static IEnumerable<T> ForEach<T>(this IEnumerable<T> items, Action<T> action){
		foreach (var item in items){
			action(item);
		}
		return items;
	}
	
}
 
 

The demo code then looks like below, where we iterate through an array of names and grab the initials of the name with some simple logic. Note usage of WhereNot predicate to avoid having to think about null strings further down the chain and also the usage of the Reduce method to get the value which the Option monad wraps.


void Main()
{
	string?[] authors = new[]{
	 "Johan Bojer",
	 null,
	 "Henrik Ibsen",
	 "Kristoffer Updahl",
	};
	
    authors.Select(x => GetInitial(x).Reduce(() => string.Empty)).ForEach(Console.WriteLine);
    
    //using ToOption() method
    authors.Select(a => GetInitial(a.ToOption())).ForEach(o => Console.WriteLine(o.Reduce(() => "?")));

	
	
}

//methods GetInitial below

Option<string> GetInitial(Option<string> name) => name.WhereNot(string.IsNullOrWhiteSpace).Map(s => s.TrimStart().Substring(0, 1).ToUpper());


The example in this article with retrieving initial (first letter) of some names is trivial. The real benefit of using the Option is to safeguard against nulls in lengthy chained calls or other scenarios where you want to always return something and decide how to indicate that we got something back and decide what an empty object will be, in the example the letter "?" signals a null based name.

Tuesday, 19 March 2024

Functional programming - Fork combinator in C# to combine results from parts

This article will discuss a wellknown combinator called Fork which allows you to combine the mapped result. Consider the following extension methods to fork on an object. Fork here means to operate on parts of the object such as
different properties and apply functions on these parts and then recombine the results into a combined result via a specified combinator function, sometimes called a 'join function'.


public static class FunctionalExtensions {

	public static TOutput Map<TInput, TOutput>(
		this TInput @this,
		Func<TInput, TOutput> func) => func(@this);

	public static TOutput Fork<TInput, TMiddle, TOutput>(
		this TInput @this,
		Func<IEnumerable<TMiddle>, TOutput> combineFunc,
		params Func<TInput, TMiddle>[] parts)
	{
		var intermediateResults = parts.Select(p => p(@this));
		var result = combineFunc(intermediateResults);
		return result;
    }

	public static TOutput Fork<TInput, TMiddle, TOutput>(
		this TInput @this,
		Func<TInput, TMiddle> leftFunc,
		Func<TInput, TMiddle> rightFunc,
		Func<TMiddle, TMiddle, TOutput> combineFunc)
	{
		var leftResult = leftFunc(@this); // @this.Map(leftFunc);
		var rightResult = rightFunc(@this); // @this.Map(rightFunc);
		var combineResult = combineFunc(leftResult, rightResult);
		return combineResult;
	}

}


Let's take a familiar mathematical example, calculating the Hypotenuse in a triangle using Pythagorean theorem. This states that the length of the longest side A of a 'right triangle' is the square root of the sum of the squares of the shorter sides B and C : A = √(B² + C²) Consider this class:
  
  
  public class Triangle {
	public double CathetusA { get; set; }
	public double CathetusB { get; set; }	
	public double Hypotenuse { get; set; }
  }
  
    
Let's test the first Fork helper extension method accepting two functions for specifying the left and right components:
  
  
  	var triangle = new Triangle
	{
		CathetusA = 3,
		CathetusB = 4
	};
	
	triangle.Hypotenuse = triangle.Fork(	
		t => t.CathetusA * t.CathetusA, 
		t => t.CathetusB * t.CathetusB, 
		(l,r) => Math.Sqrt(l+r));
		
	Console.WriteLine(triangle.Hypotenuse);
  
  
  
This yields '5' as the answer via the forked result above. A simple example, but this allows us to create a simple combinatory logic example on an object of any type using functional programming (FP). Let's look at a simpler example just combining multiple properties of an object with a simple string-join, but using the Fork version supporting arbitrary number of parts / components:
 


public class Person {
	public string JobTitle { get; set; }
	public string FirstName { get; set; }
	public IEnumerable<string> MiddleNames { get; set; }
	public string LastName { get; set; }
}

var person = new Person{
		JobTitle = "Detective",
		FirstName = "Alexander",
		MiddleNames = new[] { "James", "Axel" },
		LastName = "Foley"
	};
	
string contactCardText = person.Fork(parts => string.Join(" ", parts), p => p.FirstName,
p => string.Join(" ", p.MiddleNames), p => p.LastName); Console.WriteLine(contactCardText);
This yields: Alexander James Axel Foley Fork can be very useful in many cases you need to 'branch off' on an object and recombine parts of the object with some specific function, either two parts or multiple parts and either continue to work on the results or retrieve the results.

Sunday, 10 March 2024

Functional programming - the Tee function to inspect current state in a chained expression

In this article we will look at helper extension methods of StringBuilder first to better support chaining StringBuilder. We will work on the same StringBuilder instance and add support for appending lines or character to the StringBuilder given a condition. Also example showing how to aggregate lines from a sequence is shown and appending formatted lines. Since C# interpolation has become more easy to use, I would suggest you keep using AppendLine instead. Here is the helper methods in the extension class :


public static class StringBuilderExtensions {

	public static StringBuilder AppendSequence<T>(this StringBuilder @this, IEnumerable<T> sequence, Func<StringBuilder, T, StringBuilder> fn)
	{
		var sb = sequence.Aggregate(@this, fn);
		return sb;
	}
	
	public static StringBuilder AppendWhen(this StringBuilder @this, Func<bool> condition, Func<StringBuilder, StringBuilder> fn) => 
		condition() ? fn(@this) : @this;
		
    public static StringBuilder AppendFormattedLine(
		this StringBuilder @this,
		string format,
		params object[] args) => 
			@this.AppendFormat(format, args).AppendLine();
	
}


Now consider this example usage:


void Main()
{
	var countries = new Dictionary<int, string>{
		{ 1, "Norway" },
		{ 2, "France" },
		{ 3, "Austria" },
		{ 4, "Sweden" },
		{ 5, "Finland" },
		{ 6, "Netherlands" }
	};
	string options = BuildSelectBox(countries, "countriesSelect", true);
	options.Dump("Countries"); //dump is a method available in Linqpad to output objects 
	
}

private static string BuildSelectBox(IDictionary<int, string> options, string id, bool includeUnknown) =>
		new StringBuilder()
			.AppendFormattedLine($"<select id=\"{id}\" name=\"{id}\">")
			.AppendWhen(() => includeUnknown, sb => sb.AppendLine("\t<option value=\"0\">Unknown</option>"))
			.AppendSequence(options, (sb, item) => sb.AppendFormattedLine("\t<option value=\"{0}\">{1}</option>", item.Key, item.Value))
			.AppendLine($"</select>").ToString();   


What if we wanted to inspect the state of the stringbuilder in the middle of these chained expression. Is it possible to output state in such lengthy chained functional expressions? Yes, that is called the Tee method inside functional programming patterns. Other might call it for Tap such as used in Rx languages. The Tee method looks like this:
 
 
public static class FunctionalExtensions {

	public static T Tee<T>(this T @this, Action<T> act) {
		act(@this);
		return @this;
	}
	
}

 
We can now inspect state in the middle of chained expressions in functional expressions.
 
 
 
private static string BuildSelectBox(IDictionary<int, string> options, string id, bool includeUnknown) =>
		new StringBuilder()
			.AppendFormattedLine($"<select id=\"{id}\" name=\"{id}\">")
			.AppendWhen(() => includeUnknown, sb => sb.AppendLine("\t<option value=\"0\">Unknown</option>"))
            .Tee(Console.WriteLine)
			.AppendSequence(options, (sb, item) => sb.AppendFormattedLine("\t<option value=\"{0}\">{1}</option>", item.Key, item.Value))
			.AppendLine($"</select>").ToString();   
 
 
The picture below shows the output:
So there you have it, if you have lengthy chained functional expressions, make such a Tee helper method to peek into the state this far. The name Tee stems from the Unix Command by the same name. It copies contents from STDIN to STDOUT. More about Tee Unix command here:
https://shapeshed.com/unix-tee/

Saturday, 9 March 2024

Functional programming - looking up current time and encapsulating usings

I looked at encapsulating Using statements today for functional programming and how to look up the current time with API available on the Internet.


public static class Disposable {
	
	public static TResult Using<TDisposable,TResult>(
		Func<TDisposable> factory,
		Func<TDisposable, TResult> map)		
		where TDisposable : IDisposable
	{
		using (var disposable = factory()){
			return map(disposable);
		}
		
	}	
}

void Main()
{
	var currentTime = EpochTime.AddSeconds(Disposable
			  .Using(() => new HttpClient(),
					client => JsonDocument.Parse(client.GetStringAsync(@"http://worldtimeapi.org/api/timezone/europe/oslo").Result))
			  .RootElement
			  .GetProperty("unixtime")
			 .GetInt64()).ToLocalTime(); //list of time zones available here: http://worldtimeapi.org/api/timezone
	currentTime.Dump("CurrentTime");	
}

public static DateTime EpochTime => new DateTime(1970, 1, 1);



The Disposable is abstracted away in the helper method called Using accepting a factory function to create a TDisposable that accepts an IDisposable. We look up the current time using the WorldTimeApi and make use of extracting the UnixTime which is measured from Epoch as the number of seconds elapsed from 1st January 1970. We make use of System.Text.Json here, which is part of .NET to parse the json retrieved.

Thursday, 7 March 2024

Currying functions in C#

This article will look into helper methods for currying functions in C#. The definition of Currying consists of splitting up a function with multiple arguments into multiple functions accepting one argument. But you can also have some of the arguments provided via smaller functions, so be aware also of this alternative. What is in the name currying? The name has nothing to do with cooking from India, but comes from the mathematician Haskell Brooks Curry (!)

https://en.wikipedia.org/wiki/Haskell_Curry

A reason for introducing support for currying is that you can build complex functions from simpler functions as building blocks. Currying is explained great here:
https://www.c-sharpcorner.com/UploadFile/rmcochran/functional-programming-in-C-Sharp-currying/

We will see in the examples that we can provide multiple arguments at once and the syntax will look a bit special compared to other C# code. Curryings benefits is to allow a more flexible way to call a method. You can store into variables calls to a function providing a subset of argument and use that variable to either specify an intermediate other call or get the final result. Note - The function will be called when ALL arguments are provided ONCE ! This helps a lot of avoiding surprising side effects. Let's first look at a sample set of methods we want to support currying.


int FooFourArgs(string st, float x, int j, int k)
{
	Console.WriteLine($"Inside method FooFourArgs. Got parameters: st={st}, x={x}, j={j}, k={k}");
	return 42;
}

int FooThreeArgs(string st, float x, int j)
{
	Console.WriteLine($"Inside method FooThreeArgs. Got parameters: st={st}, x={x}, j={j}");
	return 42;
}

int FooTwoArgs(string st, float x)
{
	Console.WriteLine($"Inside method FooTwoArgs. Got parameters: st={st}, x={x}");
	return 41;
}

int FooOneArgs(string st)
{
	Console.WriteLine($"Inside method FooOneArgs. Got parameters: st={st}");
	return 40;
}


We want to call the sample methods above in a more flexible way by splitting the number of arguments we provide. Let's see the extension methods to call up to four arguments to a function. Note the use of chaining the lambda operator (=>) to provide the support for currying.


public static class FunctionExtensions
{
	public static Func<T1, TResult> Curried<T1, TResult>(this Func<T1, TResult> func)
	{
		return x1 => func(x1);
	}
	
	public static Func<T1, Func<T2, TResult>> Curried<T1, T2, TResult>(this Func<T1, T2, TResult> func)
	{
		return x1 => x2 => func(x1, x2);
	}

	public static Func<T1, Func<T2, Func<T3, TResult>>> Curried<T1, T2, T3, TResult>(this Func<T1, T2, T3, TResult> func)
	{
		return x1 => x2 => x3 => func(x1, x2, x3);
	}

	public static Func<T1, Func<T2, Func<T3, Func<T4, TResult>>>> Curried<T1, T2, T3, T4, TResult>(this Func<T1, T2, T3, T4, TResult> func)
	{
		return x1 => x2 => x3 => x4 => func(x1, x2, x3,x4);
	}
}


The following main method shows how to use these curry helper methods:


void Main()
{
	var curryOneArgsDelegate = new Func<string, int>((st) => FooOneArgs(st)).Curried();
	var curryOneArgsPhaseOne = curryOneArgsDelegate("hello");

	var curryTwoArgsDelegate = new Func<string, float, int>((st, x) => FooTwoArgs(st,x)).Curried();
	var curryTwoArgsPhaseOne = curryTwoArgsDelegate("hello");
	var curryTwoArgsPhaseTwo = curryTwoArgsPhaseOne(3.14f);

	var curryThreeArgsDelegate = new Func<string, float, int, int>((st, x, j) => FooThreeArgs(st, x, j)).Curried();
	var curryThreeArgsPhaseOne = curryThreeArgsDelegate("hello");
	var curryThreeArgsPhaseTwo = curryThreeArgsPhaseOne(3.14f);
	var curryThreeArgsPhaseThree = curryThreeArgsPhaseTwo(123);	
	//Or call currying in a single call passing in two or more parametres
	var curryThreeArgsPhaseOneToThree = curryThreeArgsDelegate("hello")(3.14f)(123);

	var curryFourArgsDelegate = new Func<string, float, int, int, int>((st, x, j, k) => FooFourArgs(st, x, j, k)).Curried();
	var curryFourArgsPhaseOne = curryFourArgsDelegate("hello");
	var curryFourArgsNextPhases = curryFourArgsPhaseOne(3.14f)(123)(456); //just pass in the last arguments if they are known at this stage
	curryFourArgsDelegate("hello")(3.14f)(123)(456); //you can pass in 1-4 parameters to FooFourArgs method - all in a single call for example or one by one
}


The output we get is this. Note that we only call the methods we defined when all parameters are sent in. The function call which had partial argument list provided did not result into a function call.


Inside method FooOneArgs. Got parameters: st=hello
Inside method FooTwoArgs. Got parameters: st=hello, x=3,14
Inside method FooThreeArgs. Got parameters: st=hello, x=3,14, j=123
Inside method FooThreeArgs. Got parameters: st=hello, x=3,14, j=123
Inside method FooFourArgs. Got parameters: st=hello, x=3,14, j=123, k=456


So from a higher level, currying a function f(x,y,z) means adding support that you could call the function like this:
f(x,g(y,z)) or f(x,g(y,h(z))) - there more arguments you get there is more variations of number of parameters and methods you can pass in. Here is another example how you can build up a calculation uing simpler methods.


void Main()
{
	Func Area = (x,y) => x*y;
	Func CubicArea = (x,y,z) => Area.Curried()(Area(x,y))(z);	
	CubicArea(3,2,4); //supplying all arguments manully is okay
}


CubicArea expects THREE arguments. The implementation allows us to use the Area function and via currying we can use that method and provide the last third argument avoiding compilation error. Currying makes your functions allow more flexible ways of being called.

Monday, 30 December 2019

More methods: Any, All, EnumerableRange, GroupBy for Linq like library written in TypeScript

I am extending my TypeScript library written to target Linq like methods, which can be used with Angular 8 and Typescript also. You can find my Github repo SimpleLinqLibraryTs here: https://github.com/toreaurstadboss/SimpleLinqLibraryTs/blob/master/src/app/array-extensions.ts

export { } //creating a module of below code
declare global {
  type predicate<T> = (arg: T) => boolean;
  interface Array<T> {
    FirstOrDefault<T>(condition: predicate<T>): T;
    LastOrDefault<T>(condition: predicate<T>): T;
    Where<T>(condition: predicate<T>): T[];
    Select<T>(...properties: (keyof T)[]): any[];
    GroupBy<T>(groupFunc: (arg: T) => string): any[];
    EnumerableRange(start: number, count: number): number[];
    Any<T>(condition: predicate<T>): boolean;
    All<T>(condition: predicate<T>): boolean;
  }
}

if (!Array.prototype.FirstOrDefault) {
  Array.prototype.FirstOrDefault = function <T>(condition: predicate<T>): T {
    let matchingItems: T[] = this.filter((item: T) => {
      if (condition(item))
        return item;
    });
    return matchingItems.length > 0 ? matchingItems[0] : null;
  }
}

if (!Array.prototype.Any) {
  Array.prototype.Any = function <T>(condition: predicate<T>): boolean {
    if (this.length === 0)
      return false;
    let result: boolean = false;
    for (let index = 0; index < this.length; index++) {
      const element = this[index];
      if (condition(element)) {
        result = true;
        break;
      }
    }
    return result;
  }
}

if (!Array.prototype.All) {
  Array.prototype.All = function <T>(condition: predicate<T>): boolean {
    if (this.length === 0)
      return false;
    let result: boolean = true;
    for (let index = 0; index < this.length; index++) {
      const element = this[index];
      if (!condition(element)) {
        result = false;
      }
    }
    return result;
  }
}

if (!Array.prototype.LastOrDefault) {
  Array.prototype.LastOrDefault = function <T>(condition: predicate<T>): T {
    let matchingItems: T[] = this.filter((item: T) => {
      if (condition(item))
        return item;
    });
    return matchingItems.length > 0 ? matchingItems[matchingItems.length - 1] : null;
  }
}

if (!Array.prototype.Select) {
  Array.prototype.Select = function <T>(...properties: (keyof T)[]): any[] {
    let result = [];
    for (let i = 0; i < this.length; i++) {
      let item: any = {};
      for (let j = 0; j < properties.length; j++) {
        let key = properties[j];
        item[key] = this[i][properties[j]];
      }
      result.push(item);
    }
    return result;
  }
}

if (!Array.prototype.GroupBy) {
  Array.prototype.GroupBy = function <T>(groupFunc: (arg: T) => string): any[] {
    let groups: any = {};
    this.forEach(el => {
      let itemKeyValue: any = groupFunc(el);
      if (itemKeyValue in groups === false) {
        groups[itemKeyValue] = [];
      }
      groups[itemKeyValue].push(el);
    });
    let result = Object.keys(groups).map(key => {
      return {
        key: key,
        values: groups[key]
      }
    });
    return result;
  }
}

function* Range(start, count) {
  for (let x = start; x < start + count; x++) {
    yield x;
  }
}

if (!Array.prototype.EnumerableRange) {
  Array.prototype.EnumerableRange = function (start: number, count: number): number[] {
    let generatedRange = [...Range(start, count)];
    return generatedRange;
  }
}


if (!Array.prototype.Where) {
  Array.prototype.Where = function <T>(condition: predicate<T>): T[] {

    let matchingItems: T[] = this.filter((item: T) => {

      if (condition(item)) {
        return true;
      }
    });
    return matchingItems;
  }
}