Monad like programming with C#.
An abstract base class Monad that extends IEnumerable, IObservable and IObserver.
Some implementations of the Monad:
- Maybe
- Identity
- List monad
- CacheMonad
- (Either is mostly untested, it is some kind of decorator) (Update: currently not working!)
Lots of extension methods (LiftMonad, Comparator functions, easy thread safe function application).
See Doc folder for detailed description an introduction.
Have a look at the Playground.cs for more examples.
A little intro how to use it:
// Creating new maybes using implicit operator overloadings
Maybe<int> justInt = 5;
// Implicit operator checks value for default(T).
// So this becomes a Nothing<int>
Maybe<int> nothingInt = 0;
var intToDoubleFunction = new Func<int, double>(x => { return x * 0.5; });
Just<double> justDouble = justInt.Fmap(intToDoubleFunction);
// Identity atomic extensions
Identity<int> intId = 5;
if(intId.CompareExchange(42, (i) => i % 2 == 1))
{
// ....
}ListMonad<int> listMonadInt = new ListMonad<int>() { 1, 2, 3, 4, 5 }; ListMonad<double> listMonadDouble = new ListMonad<double>() {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0}; listMonadInt.Fmap((x) => { return 0.5 * x;}); Func<int, double> intDoubleFunc1 = (x) => { return 0.5 * x; }; Func<int, double> intDoubleFunc2 = (x) => { return 0.7 * x; }; var lmIntDblFunc = new ListMonad<Func<int, double>>() { intDoubleFunc1, intDoubleFunc2 }; ListMonad<Double> result = listMonadInt.App(lmIntDblFunc);
Using IObserver/IObservable extensions, and ActionW/MethodW thread safe function application.
Identity<string> id = "string";
Identity<string> observer = "";
observer.Disposable = id.Subscribe(observer);
// or observer.SubscribeAt(id);
observer.NextAction = (m, x) => Console.WriteLine("Received next: " + x);
observer.CompleteAction = (m) => Console.WriteLine("Completed, last value: " + m.Return();
observer.ErrorAction = (e) => Console.WriteLine(e.Message);
// Using Subscribe from reactive extensions
id.Subscribe((s) => Console.WriteLine("Anonymour Observer Received next: " + s),
(e) => Console.WriteLine(e.Message),
() => Console.WriteLine("Completed"));
// Both lines will change the value inside the id monad.
// The observer monads OnNext will be called.
id.ActionW((i) => i.Pure("1"));
id.ActionW(() => id.Pure("2"));
public static Func<string, string> setString = (s) => s += "foobar ";
// Adding the string foobar to the current string inside the identity two times,
// in different ways.
id.MethodW(() => { return id.Pure(id.Fmap(setString).Return()); });
id.ActionW(() => id.Pure(id.Fmap(setString).Return()));
id.EndTransmission();
// Functions for combination with IMonad as result. Func<int, double, IMonad<double>> intDblIMonadDblF1 = (x, y) => { return new Just<double>((double)x + y); }; Func<int, double, IMonad<double>> intDblIMonadDblF2 = (x, y) => { return new Just<double>((double)x - y); }; Func<int, double, IMonad<double>> intDblIMonadDblF3 = (x, y) => { return new Just<double>((double)x * y); }; Func<int, double, IMonad<double>> intDblIMonadDblF4 = (x, y) => { return new Just<double>((double)x / y); }; Func<int, double, IMonad<double>> intDblIMonadDblF5 = (x, y) => { return new ListMonad<double>(){(double)x % y}; }; Func<int, double, IMonad<double>> intDblIMonadDblF6 = (x, y) => { return new ListMonad<double>() { (double)x * y * y, (double) x * y * y * y }; }; Func<int, double, IMonad<double>> intDblIMonadDblF7 = (x, y) => { return new Nothing<double>(); }; var listMonadIntDblIMonadDblFunc = new ListMonad<Func<int, double, IMonad<double>>>() {intDblIMonadDblF1, intDblIMonadDblF2, intDblIMonadDblF3, intDblIMonadDblF4, intDblIMonadDblF5, intDblIMonadDblF6, intDblIMonadDblF7}; ListMonad<int> listMonadInt = new ListMonad<int>() { 1, 2, 3, 4, 5 }; ListMonad<double> listMonadDouble = new ListMonad<double>() {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0}; Console.WriteLine("Function applying with Linq: \n" + " from f in [+, -, *, %]\n" + " from x in [1,..,5]\n" + " from y in [1.0,..,9.0] \n"+ " select f(x,y) \n"); var query = from f in listMonadIntDblIMonadDblFunc from x in listMonadInt from y in listMonadDouble select f(x, y); counter = 0; // Query is a IMonad again query.Visit((x) => { Console.Out.Write(x + ", "); counter++; if (counter % 9 == 0) Console.WriteLine(""); if (counter % (5 * 9) == 0) Console.WriteLine("------------------------------------------------"); });