Haskell, OCaml, Erlang lead the way and Rust, Zig and Go get all the mindshare. I feel like its a common pattern for more experimental languages to pioneer features and other languages to copy the features and bring them to a C style syntax that the majority of devs are familiar with.
I wish I could find the reference, but there was a great blog / article by a computer science academic basically saying that OO, procedural, and functional paradigms are extremes of a design space where the “middle” of its Pareto frontier was essentially unknown until recent advances.
Moreover, many functional languages are getting pseudo-procedural features via the like of “do” syntax and monads, but that this is in some sense a double abstraction over the underlying machine that is already inherently procedural.
Starting from a language that is already procedural and sprinkling some functional abstractions on top is simpler to implement and easier for humans to use and understand.
Rust especially showed that many of the supposed advantages of functional languages are not their exclusive domain, such as sum types and a powerful type system.
Rust and Zig brought new ideas for memory management that Haskell, OCaml, Erlang sidestep having garbage control. its honestly amazing to me that they managed to get the adoption they have while being so innovative. I say this as a fulltime elixir dev.
Pluggable allocators. Allocators are passed to functions as arguments, the caller decides exactly how memory is managed. Maybe not "new" in idea, but "new" in being consistently applied everywhere in language & libraries.
Zig forces the caller to decide since allocator is part of the function contract. And this is consistent everywhere in Zig. Effectively speaking, this is universal, explicit & mandated dependency injection for memory management as opposed to to classic C++ STL allocators.
Sorry sir, I have a nostalgic fondness for C++ - it was my first language, but it just doesn't compare for flexible allocation convenience compared to Zig.
Being first isn't necessarily good if you get it wrong, though. Laziness by default and Hindley-Milner type inference seem like mistakes that simply aren't going to get cleaned up. Other languages make their own mistakes too.
Leaving out types in public API's makes type errors hard to understand. Types should be declared in the API and bidirectional type inference used in the implementation.
Eh. This causes some problems for rust. Right now you can have a function return impl Trait instead of a concrete type. Very handy - and essentially required by async functions.
But the language also requires that types have names in lots of places. For example, you can't store an 'impl Trait' in a struct. You can't make a type alias of an impl Trait. And so on. As a result, async rust can only interact with a butchered subset of the language. (You can work around this with Box<dyn Future<...>> but performance suffers.)
There's a proposal[1] to fix this. But the proposal has been under discussion for (checks watch) 7 years now. Until this lands, async remains a second class citizen in rust.
This entire problem stems from rust's early decision to requiring concrete types at interface boundaries.
> I feel like its a common pattern for more experimental languages to pioneer features and other languages to copy the features and bring them to a C style syntax that the majority of devs are familiar with.
You're ignoring the fact that it's harder to bring new features to older languages as they have more bloat to deal with as not every idea turns into a success. So younger more focused languages can iterate more quickly. Also, being willing to make breaking changes makes things easier. Microsoft tries hard not to do that with C#.
Over time, maintaining any software becomes harder, languages are no exception. The fact that c# is still around, and still being developed is a feat in itself
I love F#. It's my go-to language and one that I work with every day. Personally I feel that IDE support (as in perf, QoL features, etc.) is the only area it lags behind C#, and outside of that it's a clear winner for everything that I want to do with it.
Microsoft management has decided CLR has a new meaning, C# Language Runtime.
VB, C++/CLI and F# are only there because existing customers.
They have always behaved as if it had been a mistake to promote F# from research project into VS 2010 as an official language.
Since then it has been something that the teams never knew how to sell to the .NET customer base, pivoting from being only libraries for C# and VB, write unit tests, Web development, data analysis, whatever might make it.
However it was Standard ML, Miranda, Hope, OCaml and Haskell that lead the way, we aren't still fully there.
Easy code is much easier in f#, a lot of the time. Hard code is usually easier in f# due to the type system helping a lot. F# is also a lot more concise.
And yes, you can combine them, but afair, only in terms project boundaries. (You can include a c# project in an f# one and vice versa). There are a few cases where it's quite useful. For example, rewriting a part of a big project in f# to leverage the imperative shell - functional core architecture. Like rewriting some part that does data processing in f#, so that you can test it easier/be more confident in correctness, while not doing a complete rewrite at once.
I don't think it's a matter of the type of problem and I always found it weird how F# is being framed as being only useful for "math-heavy" problems.
What matters is what libraries you are gonna use for your solution. If most of them are C#-only and don't have an F# equivalent then you'll lose the ergonomics and conveniences that make F# so easy to work with.
All types of problems. F# can do almost anything C# can do and with less ceremony. The quote I like is that once you get comfortable with F#, switching back to C# is like "having to fill out government forms in triplicate".
It's very possible, even encouraged when you have workloads that call for it. F# is a great functional language, so it's good for parsers, compilers, etc. The support for units of measure is also really cool, making it great for scientific computing.
C# gets all the mindshare because it's easier to understand and use on average.
We can all agree that F# is more clever and concise. No one is dying on that hill. But in terms of hacking your way through the customer requirements and working with a team of other humans, it cannot hold ground in the same way.
There is certainly not some concerted effort or lack of care involved. Microsoft could 10x the marketing budget around F# and the adoption rate probably wouldn't budge.