Skip to content

Instantly share code, notes, and snippets.

@maxgherman
Last active January 31, 2019 10:53
Show Gist options
  • Save maxgherman/19c1fb573d38a28adc4f939399413902 to your computer and use it in GitHub Desktop.
Save maxgherman/19c1fb573d38a28adc4f939399413902 to your computer and use it in GitHub Desktop.
C# List Monad
using System;
using System.Collections.Generic;
using System.Linq;
public interface IBox<TClass, out T>
{
TClass Value { get; }
}
public interface IFunctor<F>
{
// Map
IBox<F, B> Select<A, B>(IBox<F, A> initial, Func<A, B> projection);
}
public interface IApplicativeFunctor<F> : IFunctor<F>
{
// Return / Pure
IBox<F, A> Return<A>(A value);
// <*>
IBox<F, B> Apply<A, B>(IBox<F, Func<A, B>> projection, IBox<F, A> initial);
}
public interface IMonad<F> : IApplicativeFunctor<F>
{
// Bind
IBox<F, B> SelectMany<A, B>(IBox<F, A> initial, Func<A, IBox<F, B>> binding);
// Fail
IBox<F, A> Fail<A>(string error);
}
public class ListBox<T> : IBox<IEnumerable<T>, T>
{
public IEnumerable<T> Value { get; private set; }
public ListBox(IEnumerable<T> value)
{
Value = value;
}
}
public class ListMonad<T>: IMonad<T>
{
IBox<T, B> IFunctor<T>.Select<A, B>(IBox<T, A> initial, Func<A, B> projection)
{
return this.Select(initial as ListBox<A>, projection) as IBox<T, B>;
}
IBox<T, A> IApplicativeFunctor<T>.Return<A>(A value)
{
return this.Return(value) as IBox<T, A>;
}
IBox<T, B> IApplicativeFunctor<T>.Apply<A, B>(IBox<T, Func<A, B>> projection, IBox<T, A> initial)
{
return this.Apply(projection as ListBox<Func<A, B>>, initial as ListBox<A>) as IBox<T, B>;
}
IBox<T, B> IMonad<T>.SelectMany<A, B>(IBox<T, A> initial, Func<A, IBox<T, B>> binding)
{
return this.SelectMany(initial as ListBox<A>, binding as Func<A, ListBox<B>>) as IBox<T, B>;
}
// Fail
IBox<T, A> IMonad<T>.Fail<A>(string error)
{
return this.Fail<A>(error) as IBox<T, A>;
}
public ListBox<B> Select<A, B>(ListBox<A> initial, Func<A, B> projection)
{
return new ListBox<B>(initial.Value.Select(projection).ToList());
}
public ListBox<A> Return<A>(A value)
{
return new ListBox<A>(new [] { value });
}
public ListBox<B> Apply<A, B>(ListBox<Func<A, B>> projection, ListBox<A> initial)
{
var result = projection.Value.SelectMany(action => {
return initial.Value.Select(item => {
return action(item);
});
});
return new ListBox<B>(result.ToList());
}
public ListBox<B> SelectMany<A, B>(ListBox<A> initial, Func<A, ListBox<B>> binding)
{
var result = initial.Value.SelectMany(item => binding(item).Value).ToList();
return new ListBox<B>(result);
}
public ListBox<A> Fail<A>(string error)
{
return new ListBox<A>(new A[] {});
}
}
public class Computation
{
private ListBox<int> RunItem(int x)
{
return new ListBox<int>(new [] { x - 1, x , x + 1 });
}
public ListBox<int> Run()
{
var monad = new ListMonad<int>();
var initial = this.RunItem(10);
return monad.SelectMany(initial, (item => {
return monad.SelectMany(
this.RunItem(item),
(item2) => {
return this.RunItem(item2);
}
);
}));
}
}
class MainClass
{
public static void Main (string[] args) {
var box = new Computation().Run();
Console.WriteLine(string.Join(",", box.Value));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment