Skip to content

Instantly share code, notes, and snippets.

@mtranter
Created May 21, 2018 02:17
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 mtranter/d778cd313fd2c2358fd9a23bf80eac5d to your computer and use it in GitHub Desktop.
Save mtranter/d778cd313fd2c2358fd9a23bf80eac5d to your computer and use it in GitHub Desktop.
C# Task Monad(ish) - A POC.
using System;
using System.Reflection;
using System.Threading.Tasks;
namespace TaskMonad
{
public static class TaskMonad
{
public static Task<B> Select<A, B>(this Task<A> task, Func<A, B> f) => task.ContinueWith(t => t.IsCompleted ? f(t.Result) : throw t.Exception);
public static Task<B> SelectMany<A, B>(this Task<A> task, Func<A, Task<B>> f) => task
.ContinueWith(t => t.IsCompleted ? f(t.Result) : Task.FromException<B>(t.Exception.InnerException)).Unwrap();
public static Task<C>
SelectMany<A, B, C>(this Task<A> task, Func<A, Task<B>> collector, Func<A, B, C> result) =>
task.SelectMany(a => collector(a).Select(b => result(a, b)));
}
}
using System;
using System.Threading.Tasks;
using Xunit;
namespace TaskMonad.Tests
{
public class TaskMonadShould
{
[Fact]
public void ShouldMapSimplyFromAtoB()
{
var iTask = Task.FromResult(3);
var result = iTask.Select(a => a.ToString());
Assert.Equal(result.Result, "3");
}
[Fact]
public void ShouldBindSimplyFromAtoB()
{
var iTask = Task.FromResult(3);
Func<int, Task<String>> binder = i => Task.FromResult(i.ToString());
var result = iTask.SelectMany(binder);
Assert.Equal(result.Result, "3");
}
[Fact]
public void ShouldUseLinqComprehension()
{
var result = from i in Task.FromResult(2)
from j in Task.Factory.StartNew(() => i + 1)
from k in Task.Factory.StartNew(() => i * j)
select k;
Assert.Equal(result.Result, 6);
}
[Fact]
public async void ShouldPropogateExceptions()
{
var result = from i in Task.FromException<int>(new Exception("Bad Luck"))
from j in Task.Factory.StartNew(() => i + 1)
from k in Task.Factory.StartNew(() => i * j)
select k;
var ex = await Assert.ThrowsAsync<AggregateException>(() => result);
Assert.True(ex.Message.Contains("Bad Luck"));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment