Fun with pure C# and monads
We are all fascinated by pure languages like Haskell, but unfortunately have to code in C#. We could complain to our neighbor all day, but instead, what if we could also do something really pure in C#. Actually we can, it’s called LINQ:
var sum = from a in new[] { 1 }
from b in new[] { 2 }
from c in new[] { 3 }
where a + b > c
select a + b + c;
Don’t know about you, looks pretty darn pure to me. No side effects given. However, we can’t do much without side effects in the real world. In Haskell, as a pure language, we have to encapsulate all side effects into monads.
What if we wanted to write pure in C#, but also needed side effects. C# supports side effects, but only in imperative style:
Console.WriteLine(sum);
Seems legit. But to us, functional people, not much fun. What if we could write pure, but still have side effects, whenever needed. Luckily, we can define a fancy monad to help us:
public delegate T IO<out T>();
public static IO<R> SelectMany<S, C, R>(this IO<S> A, Func<S, IO<C>> foo, Func<S, C, R> bar)
{
var a = A();
var B = foo(a);
var b = B();
var c = bar(a, b);
return () => c;
}
public static IO<T> Combine<T>(IO<T> a, Action b)
{
return new Func<IO<T>, IO<T>>(x => { b(); return x; })(a);
}
public static IO<T> Where<T>(this IO<T> t, Func<T, bool> foo)
{
return () => (foo(t()) ? t : Combine(t, () => { Console.WriteLine("We screwed up!"); }))();
}
public static IO<R> Select<S, R>(this IO<S> s, Func<S, R> foo)
{
return () => new Func<IO<S>, R>(x => foo(x()))(s);
}
Now let’s do some serious pure coding with side effects:
var A = new IO<int>(() => { Console.WriteLine("A"); return 6; });
var B = new IO<int>(() => { Console.WriteLine("B"); return 7; });
var C = new IO<int>(() => { Console.WriteLine("C"); return 10; });
var sum =
from a in A
from b in B
from c in C
let x = 10
where a > b
select a + b + c + x;
Now that looks real fun to me all right.
Henceforth, you can be really sneaky, and hide side effects in places where your coworker least expects them: in pure LINQ expressions. Happy debugging!
Comments
- Anonymous
May 21, 2017
"Henceforth, you can be really sneaky, and hide side effects in places where your coworker least expects them: in pure LINQ expressions. Happy debugging!"Gee .. thanks ... that would make everyone's day productive ... I would either fire anybody that wrote code like that in C#, or quit that company altogether.- Anonymous
December 28, 2017
Yeah, it's more of a proof-of-concept, not production service code :)
- Anonymous