Skip to content

Instantly share code, notes, and snippets.

@ValdemarOrn
Last active December 18, 2015 05:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ValdemarOrn/5733734 to your computer and use it in GitHub Desktop.
Save ValdemarOrn/5733734 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Monads;
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
(10).Bind(Multiply).Bind(Stringify).Bind(Pad).Bind((x) =>
{
Console.WriteLine("Results A: " + x);
return true;
}).Wait();
Console.WriteLine("Wait blocks program execution until the invocation chain is complete");
Console.WriteLine("-------------");
(350) // Some might like the formatting better :)
.Bind(Multiply)
.Bind(Stringify)
.Bind(Pad)
.Bind((x) => {
Console.WriteLine("Results B: " + x);
return true;
}).Run();
Console.WriteLine("Run does not block and the program continues execution linearly");
Console.ReadLine();
}
// Some blocking methods to imitate real work, e.g. I/O operations, web service calls,
// or other long-running tasks.
static double Multiply(int x)
{
Thread.Sleep(1000);
return x * 2.345;
}
static string Stringify(double x)
{
Thread.Sleep(1000);
return x.ToString();
}
static string Pad(string x)
{
Thread.Sleep(1000);
return "___" + x + "___";
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Monads
{
public interface IChainElement
{
IChainElement Parent { get; }
void Run();
}
public class ChainMonad<T> : IChainElement
{
T _value;
bool HasValue;
bool HasContinuation;
AutoResetEvent NextEvent;
AutoResetEvent FinishEvent;
/// <summary>
/// Used to traverse the entity chain to find the first entity.
/// </summary>
public IChainElement Parent { get; private set; }
public T Value
{
get { return _value; }
set { _value = value; HasValue = true; }
}
private ChainMonad()
{
NextEvent = new AutoResetEvent(false);
FinishEvent = new AutoResetEvent(false);
HasValue = false;
}
public ChainMonad(T value)
: this()
{
HasValue = true;
Value = value;
}
/// <summary>
/// Starts the invocation chain.
/// If Run() is called on an entity that is not the first
/// node in the invocation chain, it traverses back until it finds
/// the first entity that does not already have a computer value.
/// </summary>
public void Run()
{
if (!HasValue)
{
StartChain();
return;
}
if (!HasContinuation)
FinishEvent.Set();
else
NextEvent.Set();
}
/// <summary>
/// Blocks program flow until the selected entity has completed its Bind() call
/// </summary>
/// <returns>Value from Bind expression</returns>
public T Wait()
{
Run();
FinishEvent.WaitOne();
return Value;
}
public ChainMonad<U> Bind<U>(Func<T, U> expression)
{
HasContinuation = true;
ChainMonad<U> next = new ChainMonad<U>();
next.Parent = this;
Task.Factory.StartNew(() =>
{
NextEvent.WaitOne();
var result = expression(Value);
next.Value = result;
next.Run();
});
return next;
}
private void StartChain()
{
IChainElement parent = this;
while (parent.Parent != null)
parent = parent.Parent;
parent.Run();
}
}
public static class Extension
{
public static ChainMonad<T> ToMonad<T>(this T val)
{
return new ChainMonad<T>(val);
}
public static ChainMonad<U> Bind<T, U>(this T val, Func<T, U> expression)
{
var monad = new ChainMonad<T>(val);
var next = monad.Bind(expression);
return next;
}
}
}

Simple Monad example for chaining code asynchronously in C#

This is a simple implementation of a function chainer in C#, using AutoResetEvent and TaskFactory to control execution flow.

The code is meant for demonstration and educational purposes. I wrote it as an experiment while studying monads. The Task Parallel Library combined with the new async/await functionality can probably give you a better way to write async code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment