Introducing Monad as a design pattern

It's quite difficult to explain Monad in an object-oriented programming (OOP) language such as C#. However, in OOP, there is one useful idea to explain Monad: design patterns. A design pattern is a reusable solution for complex problems in software design. Imagine a design pattern in architecture. Many buildings in this world must have the same pattern: doors, windows, walls, and so on. If we compare design patterns in architecture with design patterns in software design, we'll realize that they both have the same idea. In a design pattern for software design, we have functions, types, variables, and so on. These design pattern have been available in the C# language and will come together to build an application.

Considering this design pattern definition, we now have a definition of Monad itself. Monad is a type that uses a Monad pattern. And the Monad pattern is a design pattern for types.

In C#, there are some types that have actually implemented Monad naturally; they are Nullable<T>, IEnumerable<T>, Func<T>, Lazy<T>, and Task<T>. Some of these types had been discussed in the previous chapter. However, we will discuss them again in correlation with an explanation of Monad.

These five types have several things in common; obviously, they are generic types that take only one parameter, T. They implement monad naturally since they have certain rules that have certain operations provided; in other words, they are amplifiers of types. They can take a type and turn it into a special type.

We can say that Nullable<T>is an amplifier of types because it can turn, for instance, int to null, which is impossible without the use of Nullable<T> since int can only handle -2,147,483,648 to 2,147,483,647.

Let's take a look at the following code, which we can find in the AmplifierOfTypes.csproj project:

public partial class Program 
{ 
  private static Nullable<int> WordToNumber(string word) 
  { 
    Nullable<int> returnValue; 
    if (word == null) 
    { 
      return null; 
    } 
    switch (word.ToLower()) 
    { 
      case "zero": 
        returnValue = 0; 
        break; 
      case "one": 
        returnValue = 1; 
        break; 
      case "two": 
        returnValue = 2; 
        break; 
      case "three": 
        returnValue = 3; 
        break; 
      case "four": 
        returnValue = 4; 
        break; 
      case "five": 
        returnValue = 5; 
        break; 
      default: 
        returnValue = null; 
        break; 
    } 
 
    return returnValue; 
  } 
} 

The preceding code will convert the number in the string type into the int type. However, since the string type is allowed to be null, the int type will not be able to handle this data type. For this purpose, we use Nullable<int> as a return type; so now, the returning value can be null, as shown in the following code snippet:

if (word == null) 
{ 
  return null; 
} 

Then, we can invoke the preceding WordToNumber() function using the following PrintStringNumber() function:

public partial class Program 
{ 
  private static void PrintStringNumber( 
    string stringNumber) 
  { 
    if (stringNumber == null && 
      WordToNumber(stringNumber) == null) 
    { 
      Console.WriteLine( 
        "Word: null is Int: null"); 
    } 
    else 
    { 
      Console.WriteLine( 
        "Word: {0} is Int: {1}", 
        stringNumber.ToString(), 
        WordToNumber(stringNumber)); 
    } 
  } 
} 

Now, we can return null to the int data type since it has become a Nullable type, as shown in the following code snippet:

if (stringNumber == null && 
  WordToNumber(stringNumber) == null) 

The preceding code snippet will handle the null string input that is passed to the WordToNumber() function. And now we can invoke the preceding PrintStringNumber() function using the following code:

public partial class Program 
{ 
  private static void PrintIntContainingNull() 
  { 
    PrintStringNumber("three"); 
    PrintStringNumber("five"); 
    PrintStringNumber(null); 
    PrintStringNumber("zero"); 
    PrintStringNumber("four"); 
  } 
} 

If we run the PrintIntContainingNull() function, we will get the following output on the console:

Introducing Monad as a design pattern

From the preceding screenshot, you can see that we now can give the int data types' null value since it has implemented monad naturally and has been amplified using the amplifier of types.

IEnumerable<T> also implements monad because it can amplify the type of T we pass to IEnumerable<T>. Suppose we want to amplify the string type using IEnumerable<T> in order for it to be enumerated and sorted; we can use the following code:

public partial class Program 
{ 
  private static void AmplifyString() 
  { 
    IEnumerable<string> stringEnumerable 
      = YieldNames(); 
    Console.WriteLine( 
      "Enumerate the stringEnumerable"); 
 
    foreach (string s -> in stringEnumerable) 
    { 
      Console.WriteLine( 
        "- {0}", s); 
    } 
 
    IEnumerable<string>stringSorted =  
      SortAscending(stringEnumerable); 
 
    Console.WriteLine(); 
    Console.WriteLine( 
      "Sort the stringEnumerable"); 
 
    foreach (string s -> in stringSorted) 
    { 
      Console.WriteLine( 
        "- {0}", s); 
    } 
  } 
} 

In the AmplifyString() function, we are going to show that we can leverage the string type to store multiple values and represent the enumeration and sorting, as shown in the following code snippet, to initialize the enumerable string:

IEnumerable<string> stringEnumerable 
  = YieldNames(); 

We can use the following code snippet to sort the enumerable string:

IEnumerable<string> stringSorted = 
  SortAscending(stringEnumerable); 

The implementation of the YieldNames() function we use to initialize the enumerable string is as follows:

public partial class Program 
{ 
  private static IEnumerable<string> YieldNames() 
  { 
    yield return "Nicholas Shaw"; 
    yield return "Anthony Hammond"; 
    yield return "Desiree Waller"; 
    yield return "Gloria Allen"; 
    yield return "Daniel McPherson"; 
  } 
} 

And the implementation of the SortAscending() function that we use to sort the enumerable string will be as follows:

public partial class Program 
{ 
  private static IEnumerable<string> SortAscending( 
    IEnumerable<string> enumString) 
  { 
    returnenumString.OrderBy(s => s); 
  } 
} 

As you can see, in the YieldNames() function implementation, the function will yield five people-name-typed strings. These people names will be kept in the stringEnumerable variable typed IEnumerable<string>. It becomes obvious that stringEnumerable has now been leveraged so that it can handle multiple values. And in the SortAscending() function, we can see that stringEnumerable has been leveraged so that it can be sorted and ordered. If we run the preceding AmplifyString() function, we will get the following output on the console:

Introducing Monad as a design pattern

From the preceding screenshot, we can see that we have successfully amplified the string type so it can now enumerate multiple string values and can sort their values.

As we have discussed in many ways in the previous chapter, Func<T> is an encapsulate method that returns a value of the type specified by the T parameter with no need to pass any parameter. For this purpose, we will create the following Func<T> method in our AmplifiedFuncType.csproj project:

public partial class Program 
{ 
  Func<int> MultipliedFunc; 
} 

MultipliedFunc is a delegate that will take care of a function that returns the int value with no passing argument. Now, the following code will explain that Func<T> also implements monad naturally. However, before we go through with the Func<T> explanation, we are going to create a wrapper using the Nullable type we discussed earlier. Let's take a look at the following MultipliedByTwo() function:

public partial class Program 
{ 
  private static Nullable<int>MultipliedByTwo( 
    Nullable<int>nullableInt) 
  { 
    if (nullableInt.HasValue) 
    { 
      int unWrappedInt =  
        nullableInt.Value; 
      int multipliedByTwo =  
        unWrappedInt * 2; 
      return GetNullableFromInt( 
        multipliedByTwo); 
    } 
    else 
    { 
      return new Nullable<int>(); 
    } 
  } 
} 

The GetNullableFromInt() function in the MultipliedByTwo() function has the following implementation:

public partial class Program 
{ 
  private static Nullable<int> GetNullableFromInt( 
    int iNumber) 
  { 
    return new Nullable<int>( 
      iNumber); 
  } 
} 

The MultipliedByTwo() function is simple. Obviously, it will wrap the unwrapped value after we perform the multiplication operator on that unwrapped value. Suppose we have the following RunMultipliedByTwo() function:

public partial class Program 
{ 
  private static void RunMultipliedByTwo() 
  { 
    for (int i = 1; i <= 5; i++) 
    { 
      Console.WriteLine( 
        "{0} multiplied by to is equal to {1}", 
        i, MultipliedByTwo(i)); 
    } 
  } 
} 

If we run the preceding RunMultipliedByTwo() function, we will have the following output on the console:

Introducing Monad as a design pattern

From the preceding screenshot, you can see that there's a general pattern provided by the function. The unwrapped 1, 2, 3, 4, 5 will be multiplied by two and will be wrapped into 2, 4, 6, 8, 10.

Now, we are going to explain Func<T>. Let's create the following GetFuncFromInt() function, which will return the value typed Func<int>:

public partial class Program 
{ 
  private static Func<int> GetFuncFromInt( 
    int iItem) 
  { 
    return () => iItem; 
  } 
} 

The preceding GetFuncFromInt() function will generate a brand new Func<T> method from the int value. Again, we will create the MultipliedByTwo() function but with a different signature, as follows:

public partial class Program 
{ 
  private static Func<int> MultipliedByTwo( 
   Func<int> funcDelegate) 
  { 
    int unWrappedFunc =  
      funcDelegate(); 
    int multipliedByTwo =  
      unWrappedFunc* 2; 
    return GetFuncFromInt( 
      multipliedByTwo); 
  } 
} 

The preceding will successfully compile. However, suppose we have the following code:

public partial class Program 
{ 
  private static void RunMultipliedByTwoFunc() 
  { 
    Func<int> intFunc = MultipliedByTwo( 
    () => 1 + 1); 
  } 
} 

If we run the preceding RunMultipliedByTwoFunc() function, we will get the fixed result 4 rather that the formula (1 + 1) * 4. To solve this problem, we can create new code as follows:

public partial class Program 
{ 
  private static Func<int> MultipliedByTwoFunction( 
    Func<int> funcDelegate) 
  { 
    return () => 
    { 
      int unWrappedFunc =  
        funcDelegate(); 
      int multipliedByTwo =  
        unWrappedFunc * 2; 
      return multipliedByTwo; 
    }; 
  } 
} 

Using the preceding MultipliedByTwoFunction() function, the original function delegate value is kept every time the new value is requested. And now we can conclude that our previous code will use the unwrapped value and then perform some operation on it. There are differences between using the Nullable<int> operation and the Func<int>operation, such as how the wrapped type result is created. Using the Nullable monad, we can directly use the unwrapped value , perform a computation, and then produce the wrapped value. Using Func Monad, however, we have to be smarter since, as we discussed earlier, we have to produce a delegate in order to keep the previous Func Monad.

And in Monad, we can see that by multiplying two into the wrapped int, the function can produce another wrapped int so that we can call it amplification.

Creating the Monadic M<T> type

Now, we are going to implement higher-order programming in monad by refactoring our previous code. Let's take a look at the following MultipliedByTwoFunction() function, which we can find in the GeneratingMonadInCSharp.csproj project:

public partial class Program 
{ 
  private static Nullable<int> MultipliedByTwoFunction( 
    Nullable<int> iNullable, 
    Func<int,int> funcDelegate) 
  { 
    if (iNullable.HasValue) 
    { 
      int unWrappedInt = 
        iNullable.Value; 
      int multipliedByTwo = 
        funcDelegate(unWrappedInt); 
      return new Nullable<int>( 
        multipliedByTwo); 
    } 
    else 
    { 
      return new Nullable<int>(); 
    } 
  } 
} 

From the preceding MultipliedByTwoFunction() function, you can see that we now use Func<int, int>, which passes an integer argument to produce an integer result. We also get the Nullable<int> parameter directly from the argument now. And we can have the following MultipliedByTwo() function get the value of multiplying by two:

public partial class Program 
{ 
  private static Nullable<int> MultipliedByTwo( 
    Nullable<int> iNullable) 
  {  
    return MultipliedByTwoFunction( 
      iNullable, 
      (int x) => x * 2); 
  } 
} 

In the preceding MultipliedByTwo() function, we see that we define the iNullable value and the anonymous method, as shown in the following code snippet:

return MultipliedByTwoFunction( 
  iNullable, 
  (int x) => x * 2);

And suppose we have the following RunMultipliedByTwo() function to call the MultipliedByTwo() function:

public partial class Program 
{ 
  private static void RunMultipliedByTwo() 
  { 
    Console.WriteLine( 
      "RunMultipliedByTwo() implementing " + 
      "higher-order programming"); 
 
    for (int i = 1; i <= 5; i++) 
    { 
      Console.WriteLine( 
        "{0} multiplied by to is equal to {1}", 
        i, MultipliedByTwo(i)); 
    } 
  } 
} 

If we run the preceding RunMultipliedByTwo() function, we will get the following output on the console screen:

Creating the Monadic M<T> type

As you can see from the preceding screen shot, we have successfully refactored our MultipliedByTwo() function in the AmplifiedFuncType.csproj project.

Implementing the generic data type to Monad

We can also make our previous MultipliedByTwo() function more general by implementing generics, as shown in the following code:

public partial class Program 
{ 
  private static Nullable<T> MultipliedByTwoFunction<T>( 
    Nullable<T> iNullable, 
    Func<T,T> funcDelegate) 
    where T : struct 
  { 
    if (iNullable.HasValue) 
    { 
      T unWrappedInt = iNullable.Value; 
      T multipliedByTwo = funcDelegate(unWrappedInt); 
      return new Nullable<T>( 
        multipliedByTwo); 
    } 
    else 
    { 
      return new Nullable<T>(); 
    } 
  } 
} 

And if for some reason we need to have a function that passes an integer value but results in a double-for instance, and we want to divide an integer number, we can amplify that function so that it can modify the value from int to double, as shown in the following code:

public partial class Program 
{ 
  private static Nullable<R> MultipliedByTwoFunction<V, R>( 
    Nullable<V> iNullable, 
    Func<V,R> funcDelegate) 
  where V : struct 
  where R : struct 
  { 
    if (iNullable.HasValue) 
    { 
      V unWrappedInt = iNullable.Value; 
      R multipliedByTwo = funcDelegate(unWrappedInt); 
      return new Nullable<R>(multipliedByTwo); 
    } 
    else 
    { 
      return new Nullable<R>(); 
    } 
  } 
} 

And since Nullable is a amplification of type in the preceding MultipliedByTwoFunction() method, we can modify it to any other types, as follows:

public partial class Program 
{ 
  static Lazy<R> MultipliedByTwoFunction<V,R>( 
    Lazy<V> lazy, 
  Func<V, R> function) 
  where V : struct 
  where R : struct 
  { 
    return new Lazy<R>(() => 
    { 
      V unWrappedInt = lazy.Value; 
      R multipliedByTwo = function(unWrappedInt); 
      return multipliedByTwo; 
    }); 
  } 
} 

As we discussed earlier, MultipliedByTwoFunction() has a monad pattern since it passes a value of a particular type and turns it into a value of the amplified type. In other words, we have a function that has a pattern to turn a function from V to R into a function from M<V> to M<R>, where M<R> is an amplified type. This is so that we can write a method that has a Monad pattern like this:

public partial class Program 
{ 
  private static M<R> MonadFunction<V, R>( 
    M<V> amplified, 
    Func<V, R> function) 
  { 
    // Implementation 
  } 
} 

Now, we have a monadic M<T> type, which is to be used if we need to implement a Monad pattern in our function. However, if we take a look at our previous MultipliedByTwoFunction<V, R>() method, we can see that there is something we can improve in it, as shown in the following code:

public partial class Program 
{ 
  private static Nullable<R> 
  MultipliedByTwoFunctionSpecial<V, R>( 
    Nullable<V> nullable, 
    Func<V, Nullable<R>> function) 
  where V : struct 
  where R : struct 
  { 
    if (nullable.HasValue) 
    { 
      V unWrappedInt = nullable.Value; 
      Nullable<R >multipliedByTwo = function(unWrappedInt); 
      return multipliedByTwo; 
    } 
    else 
    { 
      return new Nullable<R>(); 
    } 
  } 
} 

We have modified the second parameter from Func<V, R> to Func<V, Nullable<R>>. This is done to prevent an inappropriate result, such as Nullable<Nullable<double>>, if we expect the return type Nullable<double>. We can also implement it to another type, such as Func<T>, as shown in the following code:

public partial class Program 
{ 
  private static Func<R> 
  MultipliedByTwoFunctionSpecial<V, R>( 
    Func<V> funcDelegate, 
    Func<V, Func<R>> function) 
  { 
    return () => 
    { 
      V unwrappedValue = funcDelegate(); 
      Func<R> resultValue = function(unwrappedValue); 
      return resultValue(); 
    }; 
  } 
} 

Implementing Monad to Lazy<T> and Task<T>

Besides type Func<T>, we can also implement Monad to Lazy<T> and Task<T>, as shown in the following code:

public partial class Program 
{ 
  private static Lazy<R> 
  MultipliedByTwoFunctionSpecial<V, R>( 
    Lazy<V> lazy, 
    Func<V, Lazy<R>> function) 
  { 
    return new Lazy<R>(() => 
    { 
      V unwrappedValue = lazy.Value; 
      Lazy<R>resultValue = function(unwrappedValue); 
      return resultValue.Value; 
    }); 
  } 
 
  Private static async Task<R> 
  MultipliedByTwoFunctionSpecial<V, R>( 
    Task<V> task, 
    Func<V, Task<R>> function) 
  { 
    V unwrappedValue = await task; 
    Task<R>resultValue = function(unwrappedValue); 
    return await resultValue; 
  } 
} 

Also, we can implement it for IEnumerable<T>. The code will be as follows:

public partial class Program 
{ 
  staticIEnumerable<R> 
  MultipliedByTwoFunctionSpecial<V, R>( 
    IEnumerable<V> sequence, 
    Func<V, IEnumerable<R>> function) 
  { 
    foreach (V unwrappedValue in sequence) 
    { 
      IEnumerable<R> resultValue = function(unwrappedValue); 
      foreach (R r in resultValue) 
      yield return r; 
    } 
  } 
} 

After we dissect the MultipliedByTwoFunctionSpecial() function for various data types, such as Nullable, Func, Lazy, Task, and IEnumerable, we can see that a monadic type has flattened M<M<R>> into M<R>. We can see that, when using the Nullable type, we have to avoid making Nullable<Nullable<R>> by checking whether the passing Nullable type's argument has a value. If not, just return a null Nullable<R> type, as shown in the following code snippet:

if (nullable.HasValue) 
{ 
  V unWrappedInt = nullable.Value; 
  Nullable<R> multipliedByTwo = function(unWrappedInt); 
  return multipliedByTwo; 
} 
else 
{ 
  return new Nullable<R>(); 
} 

When we use task, we also have to await the outer task and then await the inner task to avoid creating a <Task<R>> task, as shown in the following code snippet:

private static async Task<R> 
MultipliedByTwoFunctionSpecial<V, R>( 
  Task<V> task, 
  Func<V, Task<R>> function) 
{ 
  V unwrappedValue = await task; 
  Task<R> resultValue = function(unwrappedValue); 
  return await resultValue; 
} 

The other monadic types have the same pattern.

Rules of the Monad pattern

We have discussed that the Monad pattern will always wrap up a value typed T into an instance of M<T>, as shown in the following code snippet:

public partial class Program 
{ 
  private static M<T> MonadFunction <T>(Titem) 
  { 
    // Implementation 
  } 
} 

Also, in the monad pattern, we can transform the instance of M<V> to an instance of M<R> if we have a function from V to R, as shown in the following code snippet:

public partial class Program 
{ 
  private static M<R> MultipliedByTwoFunction <V, R>( 
    M<V> wrapped, Func<V, R> function) 
  { 
    // Implementation 
  } 
} 

Another rule the Monad pattern has is that we can transform the type of V to an instance of M<R> and then apply it to an instance of M<V> if we have a function from V to M<R>, as shown in the following code snippet:

public partial class Program 
{ 
  private static Func<R> 
  MultipliedByTwoFunctionSpecial<V, R>( 
    Func<V> funcDelegate, 
    Func<V, Func<R>> function) 
  { 
    // Implementation 
  } 
} 
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset