Remix.run Logo
louthy 2 days ago

In C# you can implement SelectMany for a type and that gives this:

    from id    in ParseId(inputId)
    from user  in FindUser(id)
    from posts in FindPostsByUserId(id)
    from res   in DeactivateDecision(user, posts)
    select res;
It is the equivalent to do-notation (was directly inspired by it). Here's an example from the language-ext Samples [1], it's a game of 21/pontoon.

> I wrote what you might call an acid test for monad implementations a while back: https://jerf.org/iri/post/2928/ It's phrased in terms of tutorials but it works for implementations as well; you should be able to transliterate the example into your monad implementation, and it ought to look at least halfway decent if it's going to be usable.

If I try to implement the test from your blog with Seq type in language-ext (using C#), then I get:

    Seq<(int, string)> minimal(bool b) =>
        from x in b ? Seq(1, 2) : Seq(3, 4)
        from r in x % 2 == 0
                      ? from y in Seq("a", "b") 
                        select (x, y)
                      : from y in Seq("y", "z")
                        select (x, y)
        select r;
It yields:

    [(1, y), (1, z), (2, a), (2, b)]
    [(3, y), (3, z), (4, a), (4, b)]

Which I think passes your test.

[1] https://github.com/louthy/language-ext/blob/main/Samples/Car...

jerf 2 days ago | parent [-]

It looks like it. My claim was not (and is not) that C# can't implement it, but that what is discussed in the post does not.

louthy 2 days ago | parent [-]

Fair enough :)

By the way, I happen to agree on the general point, in my blog teaching Monads in C# [1], I wrote this:

"I often see other language ecosystems trying to bring monads into their domain. But, without first-class support for monads (like do notation in Haskell or LINQ in C#), they are (in my humble opinion) too hard to use. LINQ is the killer feature that allows C# to be one of very few languages that can facilitate genuine pure functional programming."

So, yeah, regular fluent method chaining isn't really enough to make monads useful.

[1] https://paullouth.com/higher-kinds-in-csharp-with-language-e...