Skip to content

Instantly share code, notes, and snippets.

@yoshihiro503
Created November 19, 2012 12:16
Show Gist options
  • Save yoshihiro503/4110352 to your computer and use it in GitHub Desktop.
Save yoshihiro503/4110352 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
{
class TaskMonad
{
// >>= :: m a -> (a -> m b) -> m b
public static Task<B> Bind<A, B>(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 -> m b -> m b
public static Task<B> Bind_<A, B>(Task<A> ma, Task<B> mb)
{
return bind(ma, _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>(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)
{
Task<Object> delay = (Task<Object>)Delay(span);
return mplus(task, msum<A>(Enumerable.Repeat(bind_<Object, A>(delay, task), count)));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment