I thought I would add a couple of extensions to the Maybe monad to show how using monadic patterns can spread through your code when you start to use them and that is a good thing as they carry much power.
If you missed the story so far:
These new operations are extension methods. Not sure this is the correct home at the moment but until I get the repo up and running it will do :)
public static class Maybe
{
public static IMaybe<T> ToSome<T>(this T value)
=> new Some<T>(value);
public static IMaybe<T> ToMaybe<T>(this T value)
=> value == null ? Maybe<T>.None : new Some<T>(value);
public static IMaybe<T> MaybeFirst<T>(this IEnumerable<T> enumerable)
=> enumerable.MaybeFirst(_ => true);
public static IMaybe<T> MaybeFirst<T>(
this IEnumerable<T> enumerable, Func<T, bool> predicate)
=> enumerable.FirstOrDefault(predicate).ToMaybe();
public static IMaybe<TValue> MaybeFind<TKey, TValue>(
this IDictionary<TKey, TValue> dictionary, TKey key)
{
TValue value;
return dictionary.TryGetValue(key, out value)
? value.ToMaybe()
: Maybe<TValue>.None;
}
public static Func<IMaybe<T>, IMaybe<TResult>> Lift<T, TResult>(
Func<T, TResult> function)
=> maybe => maybe.Select(function);
}
So a quick run down
So lets have some fun with these extensions.
var people = // IDictionary<string, Person>
var bobsCity = people
.MaybeFind("Bob")
.SelectMany(bob => bob.HomeAddress)
.Select(address => address.City)
.Recover("Unknown")
.Value
Here we lookup Bob by name in the storage. Bob might have a home address and if so we select the address city and if we fail at any stage we return an "Unknown" address.
Goodbye fugly TryGet semantics and not a single if in the whole block even though the lookup could fail at any stage.
The use of SelectMany is interesting, this is required because the HomeAddress is a Maybe wrapped value so this requires SelectMany to flattern the lookup. Refer back to the type signatures for Select and SelectMany and the Person object and it will be obvious.
Think and how you can use IEnumerable.SelectMany on a collection of collections to flatten it . IMaybe is really a collection that can hold 0 or 1 values so the same principle apples.
As always ask if you have any questions
Happy coding
Woz