In my previous article I described how to achieve the "Maybe" monad behavior using async/await operators. This time I am going to show how to implement another popular design pattern "Reader Monad" using the same techniques.
That pattern allows implicit passing some context into some function without using function parameters or shared global objects and it can be considered as yet another way to implement dependency injection. For example:
class Config { public string Template; }
public static async Task Main()
{
Console.WriteLine(await GreetGuys().Apply(new Config {Template = "Hi, {0}!"}));
//(Hi, John!, Hi, Jose!)
Console.WriteLine(await GreetGuys().Apply(new Config {Template = "¡Hola, {0}!" }));
//(¡Hola, John!, ¡Hola, Jose!)
}
//These functions do not have any link to any instance of the Config class.
public static async Reader<(string gJohn, string gJose)> GreetGuys()
=> (await Greet("John"), await Greet("Jose"));
static async Reader<string> Greet(string name)
=> string.Format(await ExtractTemplate(), name);
static async Reader<string> ExtractTemplate()
=> await Reader<string>.Read<Config>(c => c.Template);