Skip to content

Instantly share code, notes, and snippets.

@YuriyGuts
Last active December 15, 2015 13:59
Show Gist options
  • Save YuriyGuts/5271433 to your computer and use it in GitHub Desktop.
Save YuriyGuts/5271433 to your computer and use it in GitHub Desktop.
Implementation of LINQ's Where, Select and Join extension methods in a monadic way on top of IEnumerable<T>.SelectMany binding function. (an exercise from Eric Lippert's blog post on monads: http://ericlippert.com/2013/03/25/monads-part-ten/)
static class Program
{
static void Main(string[] args)
{
var indices = Enumerable.Range(0, 26);
var alphabet = indices.Select(i => (char)('A' + i));
WriteHeader("WhereMonadic");
foreach (var item in indices.WhereMonadic(item => item % 2 == 0))
{
Console.Write("{0} ", item);
}
WriteHeader("SelectMonadic");
foreach (var item in indices.SelectMonadic(item => item % 10))
{
Console.Write("{0} ", item);
}
WriteHeader("JoinMonadic");
foreach (var item in indices.JoinMonadic(alphabet, i => i, c => c - 'A', (i, c) => new { Index = i, Character = c }))
{
Console.Write("{0} = {1} ", item.Index, item.Character);
}
Console.ReadKey(true);
}
private static void WriteHeader(string header)
{
Console.WriteLine();
Console.WriteLine();
Console.WriteLine(header);
}
// ----- SelectMany-based implementation of LINQ extension methods -----
private static IEnumerable<T> WhereMonadic<T>(this IEnumerable<T> items, Func<T, bool> predicate)
{
return items.SelectMany(item => WhereHelper(item, predicate));
}
private static IEnumerable<TProjection> SelectMonadic<TSource, TProjection>(this IEnumerable<TSource> items, Func<TSource, TProjection> projection)
{
return items.SelectMany(item => SelectHelper(item, projection));
}
private static IEnumerable<TResult> JoinMonadic<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer,
IEnumerable<TInner> inner,
Func<TOuter, TKey> outerKeySelector,
Func<TInner, TKey> innerKeySelector,
Func<TOuter, TInner, TResult> resultSelector)
{
return outer.SelectMany(outerItem => JoinHelper(outerItem, inner, outerKeySelector, innerKeySelector, resultSelector));
}
// ----- SelectMany helpers ------
private static IEnumerable<T> WhereHelper<T>(T item, Func<T, bool> predicate)
{
if (predicate(item))
{
yield return item;
}
}
private static IEnumerable<TProjection> SelectHelper<TSource, TProjection>(TSource item, Func<TSource, TProjection> projection)
{
yield return projection(item);
}
private static IEnumerable<TResult> JoinHelper<TOuter, TInner, TKey, TResult>(TOuter outerItem,
IEnumerable<TInner> inner,
Func<TOuter, TKey> outerKeySelector,
Func<TInner, TKey> innerKeySelector,
Func<TOuter, TInner, TResult> resultSelector)
{
return inner.WhereMonadic(innerItem => outerKeySelector(outerItem).Equals(innerKeySelector(innerItem)))
.SelectMonadic(innerItem => resultSelector(outerItem, innerItem));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment