Skip to content

Instantly share code, notes, and snippets.

@bleis-tift
Forked from yoshihiro503/TaskMonad.cs
Created November 20, 2012 07:18
Show Gist options
  • Save bleis-tift/4116543 to your computer and use it in GitHub Desktop.
Save bleis-tift/4116543 to your computer and use it in GitHub Desktop.
C# で非同期タスク モナド書いてみた。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Proofcafe
{
public static class TaskMonad
{
static Task<B> BindImpl<A, B>(this Task<A> ma, Func<A, Task<B>> f)
{
return new Task<B>(() =>
{
ma.Wait();
var mb = f(ma.Result);
mb.Wait();
return mb.Result;
});
}
// >>= :: m a -> (a -> m b) -> m b
public static Task<B> SelectMany<A, B>(this Task<A> ma, Func<A, Task<B>> f)
{
return ma.BindImpl(f);
}
// m a -> (a -> m b) -> (a -> b -> c) -> m c
public static Task<C> SelectMany<A, B, C>(this Task<A> ma, Func<A, Task<B>> f, Func<A, B, C> g)
{
return ma.BindImpl(x => f(x).BindImpl(y => new Task<C>(() => g(x, y))));
}
// fmap :: f a -> (a -> b) -> f b
public static Task<B> Select<A, B>(this Task<A> ma, Func<A, B> f)
{
return ma.BindImpl(x => new Task<B>(() => f(x)));
}
// >> :: m a -> m b -> m b
public static Task<B> Bind<A, B>(Task<A> ma, Task<B> mb)
{
return ma.Bind(_x => mb);
}
// mzero :: m a
public static Task<A> MZero<A>()
{
return new Task<A>(() =>
{
throw new Exception();
});
}
// mplus :: m a -> m a -> m a
public static Task<A> MPlus<A>(this Task<A> m1, Task<A> m2)
{
return new Task<A>(() =>
{
m1.Wait();
if (m1.IsFaulted)
{
m2.Wait();
return m2.Result;
}
else
{
return m1.Result;
}
});
}
// msum :: [m a] -> m a
public static Task<A> MSum<A>(IEnumerable<Task<A>> tasks)
{
return tasks.Aggregate(MZero<A>(), MPlus);
}
private static Task Delay(TimeSpan span)
{
return new Task(() => Thread.Sleep(span));
}
public static Task<A> Retry<A>(TimeSpan span, int count, Task<A> task)
{
var delay = (Task<Object>)Delay(span);
return task.MPlus(MSum<A>(Enumerable.Repeat(delay.Bind<Object, A>(task), count)));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment