Comment by raphinou
3 days ago
F# was for me the best functional language when I looked at rewriting a Ruby on Rails app. I wanted to go with a functional language, as it seems to better fit my thinking and reasoning, and I looked at Haskell, Ocaml, Scala, F#.
Being a stranger to Microsoft technologies, F# was the least likely to be chosen, but easily became the first choice. Haskell's purity made it hard to adopt (for me), Ocaml's ecosystem is subpar (there wasn't even a clear choice for a library to interact with postgresql, I couldn't install the latest version due to its reliance on an obscure tool whose name I forgot and didn't get help on the forum), and Scala is seems complex....
F# was surprisingly easy to get started with. The community is mis-managed by a corporate-minded approach (requiring people to become member of the F# software foundation to get access to the official slack!), but its members are friendly, smart and ready to help. The ecosystem is great with access to all the dotnet libraries (some complain there's a mismatch as most of those are developed for use with C#, but I rarely got in trouble for using them).
There are also great libs and frameworks available. Like https://github.com/SchlenkR/FsHttp to easily interact with http servers, to the point that I find it easier to use than a dedicated library. Or https://github.com/CaptnCodr/Fli , to run commands. And last but not least, https://www.websharper.com/ is the best web framework I have encountered across all ecosystems. Their reactive approach to web ui really allows me to develop complex interfaces in a maintainable way.
This became a longer message than I thought, probably due to my enthousiasm for the language. For complete transparency, the situation is not perfect, and in my experience the tooling is not the best.
If you want more info, I blogged about it a couple of months ago: https://www.asfaload.com/blog/consider-fsharp/
For reference, F# slack is already dead, community has moved to Discord https://discord.com/invite/fsharp-196693847965696000
Curious since you don't expand on it on the blog: in what way did Haskell's purity make it difficult to you?
Having used Haskell in production for a bit now, I don't even notice its purity. Most functions are in some kind of I/O context making it similar as other languages, except with the option of running without I/O capabilities for functions that shouldn't need it.
For me, Haskell's image and ideal of purity are what made it difficult when I started out. I tried learning the language by reimplementing a program I'd previously done imperatively, that was (in hindsight) obviously hard to do in a plain pure way, ended up learning about zippers and knot-tying to do something in a less efficient and more confusing way than just using something like STArray because I had this idea from reading about Haskell that this was not only a good way to do things, but would be magically fast because GHC. (It was not.)
These days I'd just do such a task more-or-less imperatively in Haskell, and I would be well guided by the types in doing so. But I also feel like you have to make a few such mistakes if you want to get a good intuition and taste for when it's good do things purely and when imperatively.
You gotta remember people are often picking languages based on what they can easily find out about it and extrapolating/guessing about what problems they'll run into with their expected use.
A few years ago on here I had an interesting conversation with someone who wasn't going to use rescript for something because they didn't like how it handled object types. I can't remember ever using an object type in rescript; we all just convert js objects to record type in the extern binding. But that's not information easily available to someone who has never used the language.
Same thing here I think. If you don't already have familiarity with this paradigm, it's hard to imagine what using an IO monad for side effects is like. It's not easy to tell how hard it'll be to learn it, how much it may affect the rest of your code, etc. It's easy to imagine someone (shit even me a few years ago) going "eh I'll take the language with the big easy escape hatches just in case."
> You gotta remember people are often picking languages based on what they can easily find out about it and extrapolating/guessing about what problems they'll run into with their expected use.
This is a good observation.
As someone who writes a lot of Lisp, I'm inclined to agree as the amount of people that have never written any Lisp yet immediately reject it over syntax over fears that it somehow hampers development is a (to me) surprisingly large number of people.
If I recall correctly, one of the motivating factors for Rescript was to reduce the perceived/real distance between Reason and JS in order to attract more JS devs, as Reason was so heavily associated with OCaml.
I honestly don't remember as it was +/-6 years ago. I had started learning Haskell and got to that conclusion. Maybe that I am now more versed in FP I would arrive at another conclusion? I don't know.
Another thing that was hard to grasp for me were the special operators like =<<, ., $, etc. I was using Xmonad, but those operators create a barrier to understanding exactly what happened in the file.
In the end, F# was in my (personal) experience much more approachable, and it let me learn the functional concepts along the way.
What about libraries though? They might force you to use certain monads rather than IO?
The libraries I use either have, or at least allow, IO at the base of their transformer stacks, so any IO action is a liftIO away.
Haskell taught me the important differences between IO and parity and forever influenced the way I program.
Even so the complexity here and the sheer number of mind bending concepts makes me not want to use it.
There was a large group of folks that left Ruby on Rails for Elixir (even has a similar looking syntax), yet it wasn't on your list of languages to consider. Just curious, was there a particular reason?
I should have mentioned in the message, but I was looking for a strongly typed language. I was an avid-user of dynamically-typed languages, but that particular Ruby on Rails app became unmaintainable, and part of the culprit was due to the dynamic typing. I hoped that using a statically typed language would make it easier to maintain a complex app in the long term. And I must say that it totally materialised, to the point that I don't want to develop in dynamically typed languages anymore.
Here's an example: as I said in my original message, I was a complete stranger to the dotnet ecosystem, and I learned the F# language at the same time. And I decided to develop the app as a library project to be used by the web app. I completely missed the prevalence of the async approach in the dotnet, and all my code was synchronous. One day, about half-way in the project, I realised I needed to switch to async code. Had this happened in a dynamically typed project, it would have been hell for me. Maybe it's me that can't grasp a project well enough, but I need the type-guardrails to find my way in large refactorings. And with the strong types, large refactorings can be done confidently. They don't replace tests, but make the refactoring process much more smooth.
The app is open source and its code is at: https://gitlab.com/myowndb/myowndb It doesn't have a lot of users, not the least due to lack of marketing and polishing the user experience. But I am satisfied of what I learned developing it!
This is a really minor point, but "strongly typed" and "statically typed" are not interchangeable terms. In the context of your comments here, you are exclusively interested in the static nature of the type system, rather than anything about the "strength" of it (which is something totally different and inconsistently defined).
14 replies →
These days there's Gleam[0], as a strongly typed alternative for the BEAM virtual machine. Of all the languages I haven't used yet, it seems to hit the safe + minimalistic + productive sweet spot the best. (Yes the C-inspired syntax is slightly off-putting, but syntax is the least important aspect of a language.)
[0]: https://gleam.run/
6 replies →
Hey, thank you for sharing your app's source code. I'll definitely check it out, I was really looking for such apps on F# open source projects!
Apache Spark, Delta Lake are written Scala. Being JVM based, it has a large ecosystem. Scala seems like a better choice than F#.
I'm sure it can be the better choice, but for me it was not. It seems there was some incompatibility between me and Scala. I find it such a complex language and I never managed to wrap my head around it. As I said F# was my last choice at the start of my evaluation, and Scala was high on the list due to the Java ecosystem. But in the end it didn't work out for me.
F# on the JVM would be great though!
I agree with you. I tried Scala for weeks and found it far too complex. Every line I wrote, I felt there were 5 different ways of doing it and I didn't know if I was choosing the right one. Scala tries to be too many things at once imo.
It runs on .NET, for god's sake. This is not a small platform.
2 replies →
Is F# easier to learn than Scala? (I know a bit of Scala (in the old 2.x days) but have no knowledge of F#.)
4 replies →
i've used scala for over 8 yrs everyday and i agree with your assessment.
Even intellij has no idea sometimes about what the hell is going on. It throws up compile errors when there none.
Is Frege still being developed?
I think Clojure is the better option if you want to do FP using the JVM ecosystem. The problem (for me, anyway) I've run into with Scala is that it supports both functional programming and object-oriented programming. Every code base I've worked on in Scala has ended up being a hodgepodge of both, which I find annoying.
However, the best functional programming language is, of course, Elixir. :D
> Every code base I've worked on in Scala has ended up being a hodgepodge of both
Is there something about that that has bothered you? Working in Scala codebases, I've found the best ones to work in are the ones that embrace Scala's multiparadigm nature. When programmers try to solve every problem with OO, they end up adding more and more layers to get the job done. When programmers try to solve every problem with FP, they end up resorting to sophisticated techniques that are unapproachable for other engineers. I think the simple parts of OO and the simple parts of FP go much, much further together than simple OO or simple FP can go by themselves. Have you seen something different?
1 reply →
Elixir getting a strong type system is interesting, but watch out for gleam though
But they still miss the computation expressions, which open interesting possibilities like https://github.com/CaptnCodr/Fli and https://github.com/fsprojects/FsHttp
5 replies →
Evaluated F# vs Clojure. Speed of certain algorithms just lacked for me. Value types particularly in tail recursive stacks shines in F# compared to the JVM in general. As usual YMMV
Isn't Clojure similarly (or even moreso) multiparadigm?
1 reply →
Great story! Thanks for sharing it!