HackerReposA FIELD GUIDE TO OPEN SOURCE
ProSponsor the shelf♧ 0
← Back to top all-time
louthy
csharp-monad
C#2014–2026
louthy / csharp-monad

csharp-monad

Library of monads for C#

3Distinct people
11Mentions
0Explicit recommenders
471GitHub stars
REPOSITORY AT A GLANCE

What to know before exploring

What it is

Library of monads for C#

GitHub

Where it is used

No documented product use has been verified yet.

What people are saying

No recommendation phrase was found in the indexed comments.

No classified warning is attached to this page. Read the discussions before treating silence as approval.

Also in these discussions

Mentioned in the same Hacker News threads. That is not proof they are substitutes.

This week on Hacker News

Nov 7–Nov 14 UTC · Direct repository links and separately labeled related project stories. Indexed through 11/14/2026, 3:56:07 PM UTC.

No direct repository links were found in the indexed HN discussions over the past seven days. Older discussions are available below.

Mentions over time

HN mentions by year11 dated mentions

Observed mentions: 2014-04-26 07:27:57 UTC to 2026-01-05 17:48:20 UTC.

02462014-01-01 00:00:00 UTC to 2015-01-01 00:00:00 UTC (exclusive): 6 mentions; 0 submissions, 6 comments20142015-01-01 00:00:00 UTC to 2016-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2016-01-01 00:00:00 UTC to 2017-01-01 00:00:00 UTC (exclusive): 3 mentions; 0 submissions, 3 comments2017-01-01 00:00:00 UTC to 2018-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2018-01-01 00:00:00 UTC to 2019-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2019-01-01 00:00:00 UTC to 2020-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2020-01-01 00:00:00 UTC to 2021-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments20202021-01-01 00:00:00 UTC to 2022-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2022-01-01 00:00:00 UTC to 2023-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2023-01-01 00:00:00 UTC to 2024-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2024-01-01 00:00:00 UTC to 2025-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2025-01-01 00:00:00 UTC to 2026-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2026-01-01 00:00:00 UTC to 2027-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments. Incomplete calendar period.2026*

* An incomplete calendar period is marked with an outlined bar. Its count is not directly comparable with a full period.

Counts come from the repository’s dated source evidence. Index cutoff: 2026-11-02 08:16:59 UTC.

View mention counts and date ranges
UTC ranges include their start and exclude their end. Select a period to filter the source evidence.
PeriodStart (UTC)End (exclusive, UTC)MentionsSubmissionsComments
20142014-01-01 00:00:00 UTC2015-01-01 00:00:00 UTC606
20152015-01-01 00:00:00 UTC2016-01-01 00:00:00 UTC000
20162016-01-01 00:00:00 UTC2017-01-01 00:00:00 UTC303
20172017-01-01 00:00:00 UTC2018-01-01 00:00:00 UTC000
20182018-01-01 00:00:00 UTC2019-01-01 00:00:00 UTC101
20192019-01-01 00:00:00 UTC2020-01-01 00:00:00 UTC000
20202020-01-01 00:00:00 UTC2021-01-01 00:00:00 UTC000
20212021-01-01 00:00:00 UTC2022-01-01 00:00:00 UTC000
20222022-01-01 00:00:00 UTC2023-01-01 00:00:00 UTC000
20232023-01-01 00:00:00 UTC2024-01-01 00:00:00 UTC000
20242024-01-01 00:00:00 UTC2025-01-01 00:00:00 UTC000
20252025-01-01 00:00:00 UTC2026-01-01 00:00:00 UTC000
2026 (partial)2026-01-01 00:00:00 UTC2027-01-01 00:00:00 UTC101

What Hacker News says

11 sources
Aww, thanks Mike! And thank you for the contributions and suggestions too :) > At this point basically everyone has been exposed to the concept of `Option/Result/Either/etc. and discussions typically end up revolving around the aesthetics of exception throwing vs. method chaining vs. if statements etc. without any concept of the bigger picture. I think this is a really important point. 12 years ago I created a project called 'csharp-monad' [1], it was the forerunner to language-ext [2], which I still keep on github for posterity. It has the following monadic types: Either<L, R> IO<T> Option<T> Parser<T> Reader<E,T> RWS<R,W,S,T> State<S,T> Try<T> Writer<W,T> One thing I realised after developing these monadic types was that they're not much use on their own. If your List<T> type's Find method doesn't
Read the rest
return Option<T>, then you haven't gained anything. I see others on here are taking a similar journey to the one I took over a decade ago. There's an obsession over creating Result types (Either<L, R> and Fin<A> in language-ext, btw) and the other basic monads, but there's no thought as to what comes next. Everyone of them will realise that their result-type is useless if nothing returns it. If you're serious about creating declarative code, then you need an ecosystem that is declarative. And that's why I decided that a project called "csharp-monad" was too limiting, so I started again (language-ext) and I started writing immutable collections, concurrency primitives, parsers, and effect systems (amongst others). Where everything works with everything else. A fully integrated functional ecosytem. The idea is to make something that initially augments the BCL and then replaces/wraps it out of existence. I want to build a complete C# functional framework ecosystem (which admittedly is quite an undertaking for one person). I'm sometimes a little wary about going all in on the evangelism here. C# devs in general tend to 'stick to what they know' and don't always like the new, especially when it's not idiomatic - you can see it in a number of the sub-threads here. But I made a decision early on to fuck the norms and focus on making something good on its own terms. And for those that wonder "Why C#?" or "Why not F#?", well C# has one of the best compilers and tooling ecosystems out there, it's got an amazing set of functional language features, it will have ADTs in the next version, and it has a strong library ecosystem. It also has the same kind of borrow checker low level capability as Rust [3]. So as an all-rounder language it's quite hard to beat: from 'to the metal bit-wrangling', right the way up to monad comprehensions. It should be taken more seriously as a functional language, but just generally as a language that can survive the turmoil of a long-lived project (where mostly you want easy to maintain code for the long-term, but occasionally you might need to go in and optimise the hell out of something). My approach will piss some people off, but my aim is for it to be like the Cats or Scalaz community within the larger Scala community. It's certainly a labour of love right now. But, over a decade later I'm still enjoying it, so it can't be all bad. (PS Mike, I have new highly optimised Foldable functionality coming that is faster than a regular C# for-loop over an array. Watch this space!) [1] https://github.com/louthy/csharp-monad [2] https://github.com/louthy/language-ext [3] https://em-tg.github.io/csborrow/
In Monads in C# (Part 2): Result
It's not really about Java interop, it's about low level procedural code - Clojure doesn't really look nice when doing it. It does a lot of stuff nicely but there are cases where it just feels wrong to use. But your second point is pretty much the reason why I wouldn't use Clojure in a bigger environment.I had the misfortune of working C# on a project where some smartass decided it was cool to use Maybe monad in C# using LINQ (something like https://github.com/louthy/csharp-monad) First it provided no actual value as the code was harder to read, but ignoring that - most of the developers didn't get it and just used it enough to get shit working, it was a hell to debug and maintain. core.async is public and in core - but what about when your team meber X decides to implement that - and now he sprinkles that shit all over your codebase - pe
Read the rest
ople keep using it because they don't want to argue. Clojure really lends it self to that kind of a thing where you do that "smart thing" to solve "that one problem" that ends up being a pointless mess that's hard to maintain and reason about.
In Clojure at Netflix (2013) [slides]
My pleasure :) Even though I'm fully bought into the functional and immutable idea (I have a couple of fairly popular libraries bringing the functional world to C# [1][2]), I still like to watch this video from time to time. The clarity of thought and the way he communicates the ideas is really impressive. Especially the notion of immutable structures being about managing time, and that's why the original blog is wrong. What he seems to totally miss is the fact that with immutable structures you can keep the old world and the new world: not collided and collided. And then step back in time to the not collided state. It gets far too bogged down on implementation attempts and doesn't think about the problem conceptually. [1] https://github.com/louthy/language-ext [2] https://github.com/louthy/csharp-monad
In Immutability is not enough
Agreed, there is no functional base with C# aside from LINQ. So if you want to do functional in C# you would have to chose a library, and that's why I went so far building the rest of the functional infrastructure around it. It'd be insane to use multiple Option implementations. My first attempt at bringing common monad support in C# [1] suffered from the problems you state. But that still doesn't change the crux of the blog post, it's disingenuous comparing the Option monad to a null coalescing operator. [1] https://github.com/louthy/csharp-monad
In Scala's Option monad versus null-conditional operator in C#
> That's a very cool project though Thank you :) > what got you going on that? Heh, long story... I'm a CTO of a healthcare software house in London, we've been developing a very large web-app in C# over the past 10 years. Over the years it has evolved as any project does, but I started noticing more and more that OO was really not the right tool for the job of managing large inter-dependant systems (well, the Java/C# brand of OO anyway). The promise of re-use, decoupling, composition, ... all seemed to be lies. On top of that I started to get a sense of the common bugs that were coming through: null-reference errors being by far the biggest. The in-your-face bugs like null-ref errors are relatively easy to spot though, what becomes more problematic over time is shared mutable state logic errors. They can remain buried for some time.
Read the rest
I'd already had an interest in functional programming piqued by LINQ and Erik Meijer's talks on Haskell. I spent some time learning Haskell and F#, and came to the understanding that the stability and reliability of a system could be massively improved if null didn't exist, if objects were immutable by default, and if functions were pure/referentially transparent. Expression oriented programming became my order-of-the-day, but C# kept getting in the way. Unfortunately I couldn't just drop it and move to F# because our code-base is huge and written in C#. So that's when I started writing csharp-monad [1], it was my first attempt at bringing functional concepts into C#. It had a couple of problems though, and they were: * The types were classes, and therefore if a function returned Option<T> then it could still be null * It followed the '.NET BCL way' of having functions like GetValueOrDefault() - again breaking the safety net that an Option type (for example) is supposed to give. It had benefits though, primarily that I could make composable computations with the various monads (using LINQ). The problem with that approach was that it quickly bumped up against the rest of the BCL. And, in my case, the rest of our multi-million line C# OO app. So I mothballed that project to an extent. I'd use it now and again where I had control over a process end-to-end. But it got me thinking, that the main issues I had were: 1. Non-expression based C# constructs (if/else, switch, etc.) 2. OO-heavy core types, like List<T>, Dictionary<K,V>, etc. 3. Whenever I brought in 3rd party libraries that 'did functional', they wouldn't work with my Option type in csharp-monad, or any of my functional types - and they never could because there's no baseline for functional (other than LINQ) in C#. 4. The lack of more expressive LINQ grammar makes it less useful and sometimes more cumbersome than Haskell's 'do' notation or F#'s computation expressions. 1-3 cries out for an equivalent of a BCL for functional constructs. I was under no illusion how big a job that would be, but I could see real value in it: a unified set of types for Option, Either, Try as well as collections Lst, Map, etc. "A functional prelude for C#" And once I saw that C# 6 allowed 'using static' I saw that as an opportunity to really create a 'functional BCL' that actually looks like a functional language. A chance to take C# in a more Scala-like direction (which if you think about it, is where it's going, it just doesn't have the libraries to support it). So that's when language-ext [2] was born. Item 4 was more problematic. I couldn't create more LINQ grammar. So I started thinking about it in a different way. Mostly I wanted to create expression oriented code. It was just safer. But with C# OO you always hit that expression boundary. So I thought about how I could control the boundary. Some of that was to build 'matching' constructs into the core types, but that wouldn't deal with all boundary issues. That's where the actor system comes in (LanguageExt.Process [3] ). I'd looked at Akka.net and its very Java-like API horrified me - it looked like C# 1.0. So I took the idea that a LanguageExt Process (an actor) is a fold over a stream. That suddenly created a very powerful idea that I could create packets of pure computation and wrap them with their state, and each message would evolve that state. In one fell swoop it created a better and more controlled OO that can interact with pure functions - and all fully integrated with the functional BCL I'd developed. It also allowed us to start breaking up our monolithic app in a much more controlled way. So yeah, that's the back story! Sorry if it turned into War & Peace. Btw, I am in the market for two developers at the moment. So if none of what you just read horrified you, please drop me an email with your CV to plouth AT gmail :) [1] https://github.com/louthy/csharp-monad [2] https://github.com/louthy/language-ext [3] https://github.com/louthy/language-ext/blob/master/LanguageE...
In Project Rider – A C# IDE
I haven't tried out many alternatives, but there's something about nested <> that seems to throw me off each time. I wrote a library of monads for C# [1], and implementing the SelectMany method is a good example of how messy it can be: public static RWS<R, W, S, V> SelectMany<R, W, S, T, U, V>( this RWS<R, W, S, T> self, Func<T, RWS<R, W, S, U>> bind, Func<T, U, V> project) { } I quite like F#'s alternative syntax for single type generics: Option<int> Can be written: int option Obviously it's a personal thing, so I doubt I would be able to suggest anything that would change your mind; I just had a quick go at an alternative, and I quite like this: public static SelectMany R W S T U V ( this self : RWS R W S T, bind : Func T (RWS R W S U), project : Func T U V) : RWS R W S V { } class Thing int {
Read the rest
} class Thing T : BaseThing T { } It's moot anyway really, it is what it is. I've just found it cognitively challenging over the years. [1] https://github.com/louthy/csharp-monad
In Microsoft takes .NET open source and cross-platform
I created a very similar one to you also, and found the same. It's just a bit too clunky syntactically. The only time I'd use it would be if I'm using it as part of an expression where a (switch or series of if) statement would break the expression up. As well as a generic extension on Object I started adding bespoke Match extension methods to a monads library that I've been working on [1] (which again was all about trying to coerce C# into a more expression based style). So the Option monad Match method would work like so: Func<int> res = (from x in DoSomething() from y in DoSomethingElse() select x + y) .Match( Just: v => v * 10, Nothing: 0 ); Or, the Either monad:
Read the rest
var result = (from lhs in Two() from rhs in Two() select lhs + rhs) .Match( Right: r => r * 2, Left: l => 0 ); [1] https://github.com/louthy/csharp-monad
In Draft spec for records and pattern-matching in C#

MAKE YOURSELF AT HOME

A few shortcuts

/
Search the collection
?
Open this guide
Esc
Close dialogs and navigation

Your saved repositories and interests stay in this browser.