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

language-ext

C# pure functional programming framework - come and get declarative!

20Distinct people
109Mentions
1Explicit recommenders
7.1KGitHub stars
REPOSITORY AT A GLANCE

What to know before exploring

What it is

C# pure functional programming framework - come and get declarative!

GitHub

Where it is used

No documented product use was verified in the last source check.

What people are saying

I take this approach in my language-ext project [1]. I wrote it because as well as wanting to use F#, I had a decade old C# project to maintain, and I wanted to bring…

louthy used a recommendation phrase. One indexed comment matches. This is a phrase match, not a verdict.

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, 5:04:57 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 year109 dated mentions

Observed mentions: 2014-11-19 17:06:14 UTC to 2026-09-16 19:56:17 UTC.

051015202014-01-01 00:00:00 UTC to 2015-01-01 00:00:00 UTC (exclusive): 1 mentions; 1 submissions, 0 comments20142015-01-01 00:00:00 UTC to 2016-01-01 00:00:00 UTC (exclusive): 6 mentions; 0 submissions, 6 comments2016-01-01 00:00:00 UTC to 2017-01-01 00:00:00 UTC (exclusive): 21 mentions; 2 submissions, 19 comments2017-01-01 00:00:00 UTC to 2018-01-01 00:00:00 UTC (exclusive): 14 mentions; 1 submissions, 13 comments2018-01-01 00:00:00 UTC to 2019-01-01 00:00:00 UTC (exclusive): 5 mentions; 0 submissions, 5 comments2019-01-01 00:00:00 UTC to 2020-01-01 00:00:00 UTC (exclusive): 12 mentions; 0 submissions, 12 comments2020-01-01 00:00:00 UTC to 2021-01-01 00:00:00 UTC (exclusive): 8 mentions; 0 submissions, 8 comments20202021-01-01 00:00:00 UTC to 2022-01-01 00:00:00 UTC (exclusive): 8 mentions; 0 submissions, 8 comments2022-01-01 00:00:00 UTC to 2023-01-01 00:00:00 UTC (exclusive): 3 mentions; 0 submissions, 3 comments2023-01-01 00:00:00 UTC to 2024-01-01 00:00:00 UTC (exclusive): 7 mentions; 1 submissions, 6 comments2024-01-01 00:00:00 UTC to 2025-01-01 00:00:00 UTC (exclusive): 10 mentions; 0 submissions, 10 comments2025-01-01 00:00:00 UTC to 2026-01-01 00:00:00 UTC (exclusive): 6 mentions; 0 submissions, 6 comments2026-01-01 00:00:00 UTC to 2027-01-01 00:00:00 UTC (exclusive): 8 mentions; 0 submissions, 8 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 UTC110
20152015-01-01 00:00:00 UTC2016-01-01 00:00:00 UTC606
20162016-01-01 00:00:00 UTC2017-01-01 00:00:00 UTC21219
20172017-01-01 00:00:00 UTC2018-01-01 00:00:00 UTC14113
20182018-01-01 00:00:00 UTC2019-01-01 00:00:00 UTC505
20192019-01-01 00:00:00 UTC2020-01-01 00:00:00 UTC12012
20202020-01-01 00:00:00 UTC2021-01-01 00:00:00 UTC808
20212021-01-01 00:00:00 UTC2022-01-01 00:00:00 UTC808
20222022-01-01 00:00:00 UTC2023-01-01 00:00:00 UTC303
20232023-01-01 00:00:00 UTC2024-01-01 00:00:00 UTC716
20242024-01-01 00:00:00 UTC2025-01-01 00:00:00 UTC10010
20252025-01-01 00:00:00 UTC2026-01-01 00:00:00 UTC606
2026 (partial)2026-01-01 00:00:00 UTC2027-01-01 00:00:00 UTC808

What Hacker News says

109 sources
Well, there's my super-secret future-of-software-development-and-data-autonomy project, but we're not to talk about that, so shhh! (basically my next startup idea, once I've finished inventing it). Then, there's language-ext [1], which is my large open-source functional-programming framework for C#. And although this isn't beyond the realms of an LLM: they know FP and they know C# and even my library has been around for more than a decade, so it'll be in the training data, when it comes to bending C# to my whims or to trying to eek out exceptional performance, they're all at sea. A good example would be what I am working on at the moment, which I have in a standalone prototyping repo [2]. Basically I have introduced functional traits to C#, like `Functor<F>`, `Applicative<F>`, `Monad<M>`, etc. This brings more rigour to things like LINQ
Read the rest
comprehensions and allows for the building of truly generic trait-based behaviours. Something that just doesn't really exist in C#. In language-ext today I have `Foldable<F>`, which is a little bit like `IEnumerable`, but pure. I want to be able to provide a super efficient set of default implementations for any `Foldable` (or enumerable/iterable). For this I need an efficient lazy-stream or co-routine system. The one built-in to C# (`IEnumerable` and `IEnumerator`) is impure (it mutates as it enumerates), so I am trying to build an efficient iterator/enumerator that: * Takes around 0.25 nanoseconds per-iteration-step for its housekeeping (this speed is then on a par with the mutable IEnumerators that are a core part of C#). * Doesn't allocate any memory * Is immutable * Is lazy * Can be stopped at any point and the iterator reference be passed around (because it's immutable) * Can be composed with standard functional operators (functor map, applicative apply, monad bind, etc.) without performance degradation and without a large memory-allocation cost. I've been building several prototypes to try different ways of bending C# to my whims. I've managed all but the last item on that list. Not allocating memory means using value-types (stack allocated types), but that also means the entire state of the co-routine needs to be stored in the value-type as each value is yielded (because control needs to be given back to whatever code is processing the values). To solve it, I'm pretty much building my own runtime, stack-machine, and memory manager on top of the .NET CLR so that I don't have to submit to its rules. I'm trying to apply as many of my old-skool low-level engineering chops as I can (without making it brittle); but to do the last item on that list needs more space in a value-type than would be reasonable (to avoid copying costs), so I'm looking at other pooling strategies and into building lots of bespoke to-the-metal memory managers. After all of that, it may be a fools errand, and not doable. The LLM wouldn't understand, and that's for just one feature! Also, it must be stated, I just love doing this shit, it's brain fuel. The idea of having this conversation endlessly with an LLM as it continuously gets it wrong is nightmare fuel. I'm not anti-AI, I love the fact that people who can't, now can. But, at this point in my journey with code, I think quicker and can produce quicker than an LLM. I think it's akin to a virtuoso piano player. If the piano player had to describe what they wanted to an LLM, the magic would go, the enjoyment would go, and potentially the quality would go. It would it also take much longer than if they had just played. That's how I feel with code. An LLM can maybe churn out more code than me, but I can build more value and I can invent. And when in my flow state, nothing can stop me. I will certainly keep checking in though, I'm sure there'll be a point where I feel like it augments me rather than hinders. It's just not there for me yet. Too much information? :D [1] https://github.com/louthy/language-ext [2] https://github.com/louthy/iterator-prototype (this is messy prototype code, don't hate me).
In Small programming tricks
Sorry, I mean that writing functional code in C# is way more verbose than in Kotlin. C# is already more verbose because it lacks things like union types (and so you need to have a fallback branch in every switch) and for example everything needs to be nested in a class. Then you also have the fact that there is no "val" keyword (which makes things clearer imo) and the fact that it's generics type inferencing is only based on method arguments, which really adds a lot of noise to almost all generic functions. I was using LanguageExt [0] in C# and I am now using Arrow [1] in Kotlin, and while LanguageExt is really nice for addressing some C# shortcomings, for me this is night and day. [0] https://github.com/louthy/language-ext [1] https://arrow-kt.io/
In Voxile: A ray-traced game made in its own engine and programming language
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
I'm glad Paul Louth of https://github.com/louthy/language-ext/ is here in the comments. 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. LanguageExt really presents a unified vision for and experience of Functional Programming in C# for those are who truly interested, akin to what's been going on in the Scala ecosystem for years. I've been using it and following its development for a few years now and it continually impresses me and makes C# fresh and exciting each day.
In Monads in C# (Part 2): Result
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, str
Read the rest
ing)> 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...
In Monads in C# (Part 2): Result
I think you're describing part of the bind function, which is part of the definition of the monad interface: a -> m b But the full definition is: bind :: (a -> m b) -> m a -> m b In C#, it would look like this: M<B> Bind(Func<A, M<B>> f, M<A> ma) Assuming a future version of C# that supports higher-kinds that is. In my language-ext library, I achieve a higher-kinded monad trait [1], like so: public interface Monad<M> : Applicative<M>, where M : Monad<M> { static abstract K<M, B> Bind<A, B>(K<M, A> ma, Func<A, K<M, B>> f); } Which is what the original comment is about. Most people in C# are not creating monads when they implement Bind or SelectMany for their type. They are simply making 'do-notation' work (LINQ). The monad abstraction isn't there until you define the Monad trait that allows the w
Read the rest
riting of any function constrained to said trait. For example, a `When` function that runs the `then` monad when the `predicate` monad returns `true` for its bound value: public static K<M, Unit> When<M>(K<M, bool> predicate, K<M, Unit> then) where M : Monad<M> => predicate.Bind(flag => flag ? then : M.Pure(unit)); This will work for any monad, `Option`, `List`, `Reader`, ... or anything that defines the trait. So types like `Option` are just pure data-types. They become monads when the Monad trait is implemented for them. The monad trait can be implemented for data-types and function-types. Reader, for example, has the Monad trait implemented for the function: Func<E, A> btw, monads also inherit behaviour from applicative and functor. The ability to lift pure values into the monad (a -> m a) is vital to making monads useful. This is `select` in LINQ, `pure` in Haskell's Applicative, and `Pure` in language-ext's Applicative [2]. [1] https://github.com/louthy/language-ext/blob/main/LanguageExt... [2] https://github.com/louthy/language-ext/blob/main/LanguageExt...
In Monads in C# (Part 2): Result
This is all very basic, instead you can use C#'s new static interface methods feature to create higher-kinded traits where you can properly generalise over a monad trait (or applicatives, functors, foldables, etc.), which is what I do in language-ext [0]. I'm not saying that implementing SelectMany for specific data-types isn't valuable. It certainly ends up with more elegant and maintainable code, but the true power of monads and other pure-FP patterns opens up when you can fully generalise. * I have a blog series on it that covers implementing Semigroups, Monoids, Functors, Foldables, Traversables, Applicatives, Monads, and Monad Transformers (in C#) [1] * The monad episode (my 'Yet Another Monad Tutorial') [2] * An entire app generalised over any monad where the monad must support specific traits [3]. It's the program I use to send o
Read the rest
In Monads in C# (Part 2): Result
I'm the author of language-ext [1] a pure functional framework for C# and have been pushing the declarative programming thing in C# for over decade. C# is a great language for declarative programming and LINQ is awesome. You need to constrain yourself (and your team) so you don't fall into bad habits, but it can really pay dividends in terms of code stability/maintainability. I have a couple of samples that I think might surprise you if you think C# must look like Java... * A game of pontoon [2] - I create a Game monad which is an alias for a monad-transformer stack of StateT > OptionT > IO. This shows how terse you can get, where the code almost turns into a narrative. * Newsletter sender [3] (which I use for my blog) [4] - This generalises over any monad as long as the trait requirements are met. This is about as declarative as you c
Read the rest
In LINQ and Learning to Be Declarative
As the author of language-ext [1] (functional programming library for C#) -- these suggestions are a big "YES!!!!!" from me. I assume they're doing the first one due to the way they're using static interfaces like traits (which is what I also do to support Functor, Applicative, Monad, etc. traits). Being able to refine the type-checker based on constraints would be a huuuge win. Although, I'd prefer higher-kinds :) The second one has been a big ballache when using pattern-matching. I think the leading `.` on the patterns isn't pretty, but I'd take it over handwriting the full type name every time. [1] https://github.com/louthy/language-ext/
In C# Language Design Meeting for June 30th, 2025
Nope, pure functions are referentially transparent. The key idea is that you can replace the function invocation with a value and it shouldn’t change the program. A regular static function could refer to a file, a database, or it could change some global memory, etc. So, replacing the static function (that causes side-effects) with a pure value wouldn’t result in the same program. Side-effects are usually declaratively represented by something like an IO monad. Which in reality is just a lambda with the side-effecting behaviour in the body of the lambda. So, to make a pure IO function you don’t actually perform the IO in the function, you return a data type (the lambda) that represents the IO to perform. This maintains the purity if the function and ‘passes the buck’ to the caller. In the case of Haskell, all the way up to its Main functi
Read the rest
on and into its runtime — making the language itself pure, even if the runtime isn’t. This isn't just a Haskell thing though. I'll write code this way in C# (and have built a large pure-FP framework for C# to facilitate this approach [1]). Here's an example of the more 'narrative style' [2] of C# using pure-FP. It reads from top-to-bottom, keeping the related functions near each other and walking the reader through the functionality. There's also a massive removal of the usual clutter you see in C#/Java programs, getting down to the essence of the logic. It won't be to everybody's taste (as it's not idiomatic at all), but it demonstrates the idea. This style works well for regular program logic and less well for things like APIs where there's not always a narrative you can tell. [1] https://github.com/louthy/language-ext [2] https://github.com/louthy/language-ext/blob/main/Samples/Car...
In What makes code hard to read: Visual patterns of complexity (2023)

Showing the 15 most recent of 109 sources. Enable JavaScript to search and browse every indexed mention.

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.