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:


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!