Skip to content

Instantly share code, notes, and snippets.

@xfire
Created February 2, 2012 20:05
Show Gist options
  • Save xfire/1725458 to your computer and use it in GitHub Desktop.
Save xfire/1725458 to your computer and use it in GitHub Desktop.
first attempt of the writer monad for c#/linq
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