Created
February 2, 2012 20:05
-
-
Save xfire/1725458 to your computer and use it in GitHub Desktop.
first attempt of the writer monad for c#/linq
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Linq; | |
using System.Text; | |
using System.Collections.Generic; | |
namespace WriterMonadExample | |
{ | |
public interface Monoid<T> | |
{ | |
T Mempty { get; } | |
T Mappend(T a, T b); | |
T Mconcat(IEnumerable<T> xs); | |
} | |
class NormalMonoid<T> : Monoid<T> | |
{ | |
private readonly T _mempty; | |
private readonly Func<T, T, T> _mappend; | |
public NormalMonoid(T mempty, Func<T, T, T> mappend) | |
{ | |
_mempty = mempty; | |
_mappend = mappend; | |
} | |
public T Mempty { get { return _mempty; } } | |
public T Mappend(T a, T b) { return _mappend(a, b); } | |
public T Mconcat(IEnumerable<T> xs) { return xs.Aggregate(_mempty, _mappend); } | |
} | |
struct Writer<TLog, TV> | |
{ | |
public readonly TLog Log; | |
public readonly TV Value; | |
public Writer(TLog log, TV v) | |
{ | |
Log = log; | |
Value = v; | |
} | |
} | |
static class WriterExt { | |
// public static Writer<TLog, TV> Tell<TLog, TV>(this TLog w) | |
public static Monoid<T> Create<T>(T mempty, Func<T, T, T> mappend) { return new NormalMonoid<T>(mempty, mappend); } | |
public static Monoid<IEnumerable<T>> Enumerable<T>() { return Create(Enumerable.Empty<T>(), (xs, ys) => xs.Concat(ys)); } | |
public static Writer<IEnumerable<TL>, TR> ToWriter<TL, TR>(this TR value) { | |
return new Writer<IEnumerable<TL>, TR>(Enumerable<TL>().Mempty, value); | |
} | |
public static Writer<IEnumerable<TL>, TR> Select<TL, TV, TR>(this Writer<IEnumerable<TL>, TV> w, Func<TV, TR> f) | |
{ | |
return new Writer<IEnumerable<TL>, TR>(w.Log, f(w.Value)); | |
} | |
public static Writer<IEnumerable<TL>, TR> SelectMany<TL, TV, TR>(this Writer<IEnumerable<TL>, TV> a, Func<TV, Writer<IEnumerable<TL>, TR>> selector) | |
{ | |
var n = selector(a.Value); | |
return new Writer<IEnumerable<TL>, TR>(Enumerable<TL>().Mappend(a.Log, n.Log), n.Value); | |
} | |
public static Writer<IEnumerable<TL>, TR> SelectMany<TL, TV, TM, TR>(this Writer<IEnumerable<TL>, TV> a, Func<TV, Writer<IEnumerable<TL>, TM>> s, Func<TV, TM, TR> r) | |
{ | |
return a.SelectMany(x => s(x).SelectMany(y => new Writer<IEnumerable<TL>, TR>(Enumerable<TL>().Mempty, r(x, y)))); | |
} | |
} | |
public static class WriterMonadMain | |
{ | |
static Writer<IEnumerable<string>, int> Tell(string msg) { | |
return new Writer<IEnumerable<string>, int>(new List<string>() {msg}, default(int)); | |
} | |
static Writer<IEnumerable<string>, int> Plus2(int value) { | |
return from i in value.ToWriter<string, int>() | |
from _ in Tell(value +" + 2") | |
select i + 2; | |
} | |
static Writer<IEnumerable<string>, int> Plus3(int value) { | |
return from i in value.ToWriter<string, int>() | |
from _ in Tell(value + " + 3") | |
select i + 3; | |
} | |
public static void Main() | |
{ | |
var r = from i in 1.ToWriter<string, int>() | |
from a in Plus2(i) | |
from _1 in Tell("after plus 2") | |
from b in Plus3(a) | |
from _2 in Tell("after plus 3") | |
select b; | |
Console.WriteLine(" -> " + r.Value); | |
Console.WriteLine(" [" + string.Join(", ", r.Log) + "]"); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment