Functor
Not only can you turn Nullable<T>
into a functor, but C# actually understands functors, enabling you to write something like this:
x = from x1 in x
select Foo(x1);
If you prefer method call syntax, that's also possible:
x = x.Select(Foo);
In both cases, you need an extension method like this:
public static TResult? Select<T, TResult>(
this T? source,
Func<T, TResult> selector) where T : struct where TResult : struct
{
if (!source.HasValue)
return null;
return new TResult?(selector(source.Value));
}
Monad
Not only does C# understand functors, but it understands monads as well. Add these SelectMany
overloads as well:
public static TResult? SelectMany<T, TResult>(
this T? source,
Func<T, TResult?> selector)
where T : struct
where TResult : struct
{
if (!source.HasValue)
return null;
return selector(source.Value);
}
public static TResult? SelectMany<T, U, TResult>(
this T? source,
Func<T, U?> k,
Func<T, U, TResult> s)
where T : struct
where TResult : struct
where U : struct
{
return source
.SelectMany(x => k(x)
.SelectMany(y => new TResult?(s(x, y))));
}
This enables you to write queries like this:
var result = from x in (int?)6
from y in (int?)7
select x * y;
Here, result
is an int?
containing the number 42
.