This is very neat, I love the idea of using the syntax tree to guide what can be parallelized vs. not.
As some additional background, there's a very good reason why the F# language typechecks files sequentially. Because F# supports type inference at every scope, a single change in the body of a function can result in cascading type changes across an entire project. This kind of change can not only affect other files, but other files inside of other projects in the same solution.
A way to curb these kinds of cascading changes is explicit type annotations and/or signature files, which "lock" the type signature for a given construct/file. And the F# compiler has had optimizations in place when signature files are used to know when to re-check stuff based on this. However, these didn't extend to the sequential typechecking of files, and for the large majority of codebases that don't use signature files, these optimizations didn't really kick in anyways.
That's interesting. In Haskell top-level annotations are not required but I don't think I've ever seen a real project without them - its basically a community standard that's universally adopted, in a community that doesn't adopt many standards.
It's useful to keep these anyway, as if you make a change that accidentally changes the type of some function, the error message makes it immediately obvious what you did. Otherwise it's hard to tell whether you messed up the function or the caller.
Also having type annotations makes code reviews easier. Basically people's brains can use the same optimization that compilers do.
There is also a helpful compiler command to generate updated signature files for you. Then you just glance at the git changes and see if you accidentally broke an API or not.
We've been building a very technical product in F# + Rust for the last three years or so (think R lang + R Studio or Replit but for DSLs we built for finance and contracts).
While most folks tend to see F# as a .NET-oriented/back-end kind of language, they'd be missing some incredibly unique web technologies such as the Fable compiler (F# -> JS, Python, Dart, etc) and Elmish (Elm, but for F# with a JS target via Fable). It boggles my mind that more of the web dev community haven't discovered these tools.
These "communities" fall completely outside of MSFT's umbrella, but are transformative for how you think about architecting applications: Elm as an architecture (rather than as a language) enables a large amount of optionality in terms of what technologies one might use as a "reactivity layer" (e.g. can swap out React for SolidJS or even non-JS targets like Avalonia quite easily if it made sense to).
Our bet is that it enables us to future proof things in a number of unique ways as better WASM-based solutions come online as well that hopefully won't require shipping the whole .NET runtime (e.g. Bolero). The approach is also v helpful in managing state across an otherwise very complex application.
I looked at Fable and the resulting code just looked way more complicated than anything Javascript could write. I'm interested in F# still on the backend, but I don't think people "haven't discovered" Fable, it's just not a great alternative.
Yeah, I suppose it depends on what you're building.
Three years of building with it (plus constant re-evaluation of that decision) has supports our conclusion that it is far more concise and easier to manage (esp for less technical folks who need to sign off on the business logic/domain) than anything we'd have done in JS.
With that said, we're building a product that requires much more interactivity than most, and we're performing a lot of typical "back-end" logic in the client - that might color our evaluation.
To be sure, it hasn't been without tradeoffs, but we haven't found those tradeoffs to be at the language level.
FWIW the benefit tends to come in the long run. Same argument as TypeScript, really. You add some conceptual overhead to get code that fails less in the face of change, better refactoring, etc.
Is it really appreciably different from "transpilation" with TypeScript?
Like, I have seen a little of both (I've used a lot of TypeScript, but who actually looks at the output JS lol), and while I agree the JS output from Fable seemed surprisingly verbose, I'm not sure I see how it practically matters unless one is worried about bundle size or something.
> In theory Elm is just such a fascinating project... if it was not held back by the people developing it.
PureScript may be worth a look, it’s got several features that were rejected by Elm devs: typeclasses, ability to publish modules that use FFI to JS, runs server-side, etc.
Please PLEASE enough with the character assassination of the Elm guy.
He wants to run his own project his own way.
There's a small but dedicated residue of people who just can't stand being told "no" and go around crapping on the kid whenever they get a chance.
I get it. You don't like Evan's project management style. Move on already.
- - - -
The fact of the matter is that he's a person who took his thesis, made it into a product, and got traction in the real world. People have used Elm to make things. Things that go.
How many of us can say the same?
And that's before you get to all the fascinating and as yet still-too-obscure things that the OP talks about. Things that are in part a little more widely known and understood thanks to Elm project.
F# is my go-to language for new backend projects and console apps. You can be as functional as you like, with imperative/mutable/OOP escape hatches available for those rare but unavoidable times you need them
Have to agree. Recently decided to try out Python instead. Everyone at work wanted Python, it's popular, so why not give it a shot. In constant regret, missing the type checking in F#.
for console apps, F# sadly suffers from general .NET issues for console apps. Very large size (>150MB for a simple app) and at least 400-700msec startup time
I concur. All the .NET devs seem to prefer C# and are afraid to go near F#. It seems to be out of their comfort zone.Once people learn to code one way, they
often don't want to try new things, since C# works and pays the bills, they don't even try F#.
If you look at the JS - that's of-course the production minimized build, the transpiled JS is pretty nice and readable.
Super simple site - vanilla JS seems wonderfully easy with F#, easy to hide its warts and build easy re-usable items.
But there's of course also smarter stuff with two-way bindings via html annotation and builders etc. I am actually using Feliz.ViewEngine, which is building the HTML using F#, but only for the navigation bar. Might try converting a page to it.
Noob question. I developed projects in OCaml (ocaml + opam + merlin + core/async) on linux/macos. I'm clueless about F#, I've always thought of that as some sort of JVM for Windows, not great for Linux. How would my experience compare if I was to use F#? not so much in term of language, but developer experience: IDE integration, richness of stdlib and third-party libs, build system, package management, tools stability.
I only tried F# for few days, but it was a pleasant experience on both macos and linux.
dotnet CLI should take care of build process, it can even generate self-sufficient executable (that bundle parts of .NET in them). The infamous required XML boilerplate has also been cut down to near-zero.
My biggest gripe is that Microsoft's debugger is closed-source and proprietary (though free for users of official VSCode builds). There is open-source netcoredbg by Samsung, so you can use VSCod[e,ium] with https://open-vsx.org/extension/muhammad-sammy/csharp , but YMMV.
JetBrains Rider is really excellent until you start getting up to like the 30-project mark. Stdlib is very extensive although has a bunch of annoying quirks due to being like twenty years old and due to having Linux retrofitted onto it; I have personally had to reimplement parts of its API from syscalls, but if performance isn't super-important for you then it's OK. MsBuild (the build system) and NuGet (the package manager) are both absolutely cursed, but if you are doing totally vanilla things then they're usable out of the box. The `dotnet` command line tools are weirdly inconsistent, sometimes buggy, and full of edge cases even in the places where they are self-consistent, but again if you're doing something super-vanilla then they should be fine.
I’ve never ran into an issue with 30+ projects open though I question why one would have so many in one project in the first place personally, but I never had an issue
F# also has an alternative toolchain based around Paket[0] and Fake[1]
YMMV with the build and package system depending on your experience. Sheet staying my career writing with JVM languages and then moving to C#, I far prefer MSBuild + NuGet over Maven or Gradle. But I know lots of folks who feel the opposite, so maybe it's just a matter of preference.
I primarily use F# on linux and the experience is very smooth.
editor: VSCode + ionide extension
stdlib: F# has its own stdlib but it can also access all of dotnet's stdlib seemlessly.
libs: Many of the 3rd party libs are written in C# in an OOP style but you can still use them. Most of the popluar ones have functional F# wrappers if you don't like OOP.
build: the dotnet cli is very advanced and not too hard to grok.
I haven't used F#, but I have had to build OCaml programs from source on Linux and my god OPAM is the worst thing since Autotools. Maybe worse - Autotools actually works!
OPAM - despite the appearance of a modern language management tool - seems to fuck things up almost every time I use it. And not just me. The amount of time I was spending helping coworkers fight it got so much I gave up and just added a caching system so they wouldn't have to deal with the pain of OCaml at all.
So if F# manages to improve on that even slightly I'd say it's definitely worth switching to!
Plus it's more portable than OCaml, which seems to view working on the most popular desktop OS in the world as beneath it.
F# is very cross-platform at this point because .NET 7 is very cross-platform. To install F# just install the .NET SDK. JetBrains Rider and VS Code with Ionide are the two cross-platform IDEs.
This is the type of feature that makes me want to use F#. Really great work, I would love to see similar work replicated in other languages (python's type checking libs especially). As an outsider it feels like the Bazel/Buck/Pants approach applied to type checking
Can anyone recommend a good hard copy book for F#? One that covers the syntax, language features, and covers functional programming fundamentals along the way?
Like, the F# book that Brian Kernighan would write?
I would recommend two. F# in Action [1] by Isaac Abraham is a great (and recent) introduction to the F# language. For a more philosophical, domain-oriented book, you can't go wrong with Scott Wlaschin's Domain Modeling Made Functional book[2]. Scott's blog[3] is also must-read material.
I had discovered Scott’s blog in the last couple of days while searching for resources related to writing lexers and parsers in F#. It is indeed a great resource!
Thank you for your other recommendations, I’ve just ordered both books!
He named UNIX, he invented the "Hello, world!" program, he's the K in K&R (The C Programming Language), he's the K in AWK, and he's the co-author of other classic works like The UNIX Programming Environment and more recently The Go Programming Language. He's currently a CS professor at Princeton.
EDIT: Why the downvotes? It's just terse, it's not at all rude.
Several other books that are good have been mentioned, I'll throw in one more, Stylish f# 6 by Kit Eason. He does a good job covering things and it covers features up through the .NET 6 version of F# so less stuff to learn once you're done with it.
As some additional background, there's a very good reason why the F# language typechecks files sequentially. Because F# supports type inference at every scope, a single change in the body of a function can result in cascading type changes across an entire project. This kind of change can not only affect other files, but other files inside of other projects in the same solution.
A way to curb these kinds of cascading changes is explicit type annotations and/or signature files, which "lock" the type signature for a given construct/file. And the F# compiler has had optimizations in place when signature files are used to know when to re-check stuff based on this. However, these didn't extend to the sequential typechecking of files, and for the large majority of codebases that don't use signature files, these optimizations didn't really kick in anyways.
Also having type annotations makes code reviews easier. Basically people's brains can use the same optimization that compilers do.
We've been building a very technical product in F# + Rust for the last three years or so (think R lang + R Studio or Replit but for DSLs we built for finance and contracts).
While most folks tend to see F# as a .NET-oriented/back-end kind of language, they'd be missing some incredibly unique web technologies such as the Fable compiler (F# -> JS, Python, Dart, etc) and Elmish (Elm, but for F# with a JS target via Fable). It boggles my mind that more of the web dev community haven't discovered these tools.
These "communities" fall completely outside of MSFT's umbrella, but are transformative for how you think about architecting applications: Elm as an architecture (rather than as a language) enables a large amount of optionality in terms of what technologies one might use as a "reactivity layer" (e.g. can swap out React for SolidJS or even non-JS targets like Avalonia quite easily if it made sense to).
Our bet is that it enables us to future proof things in a number of unique ways as better WASM-based solutions come online as well that hopefully won't require shipping the whole .NET runtime (e.g. Bolero). The approach is also v helpful in managing state across an otherwise very complex application.
Three years of building with it (plus constant re-evaluation of that decision) has supports our conclusion that it is far more concise and easier to manage (esp for less technical folks who need to sign off on the business logic/domain) than anything we'd have done in JS.
With that said, we're building a product that requires much more interactivity than most, and we're performing a lot of typical "back-end" logic in the client - that might color our evaluation.
To be sure, it hasn't been without tradeoffs, but we haven't found those tradeoffs to be at the language level.
Like, I have seen a little of both (I've used a lot of TypeScript, but who actually looks at the output JS lol), and while I agree the JS output from Fable seemed surprisingly verbose, I'm not sure I see how it practically matters unless one is worried about bundle size or something.
In theory Elm is just such a fascinating project... if it was not held back by the people developing it.
* Elmish (F#) repo - https://github.com/elmish/elmish
* The Elmish Book (... remarkably good) - https://zaid-ajaj.github.io/the-elmish-book/#/
* Fable compiler - https://fable.io/
The F# community is very friendly (sub-communities as well), and there are plenty of good opportunities to contribute OSS work across any skill level.
Phosphor isn't hiring right now, but we will begin a search for FE/interface engineers soon. oliver@phosphor.co for anyone interested.
PureScript may be worth a look, it’s got several features that were rejected by Elm devs: typeclasses, ability to publish modules that use FFI to JS, runs server-side, etc.
He wants to run his own project his own way.
There's a small but dedicated residue of people who just can't stand being told "no" and go around crapping on the kid whenever they get a chance.
I get it. You don't like Evan's project management style. Move on already.
- - - -
The fact of the matter is that he's a person who took his thesis, made it into a product, and got traction in the real world. People have used Elm to make things. Things that go.
How many of us can say the same?
And that's before you get to all the fascinating and as yet still-too-obscure things that the OP talks about. Things that are in part a little more widely known and understood thanks to Elm project.
Deleted Comment
(mac, linux, windows, ios, android, web)
https://github.com/fsprojects/Avalonia.FuncUI
Here build times are not really an issue as it seems to be hot-transpiling to js, so save and site is reloaded almost instant (at least small sites):
My small tools site built with Fable: https://peheje.github.io/compare.html
If you look at the JS - that's of-course the production minimized build, the transpiled JS is pretty nice and readable.
Super simple site - vanilla JS seems wonderfully easy with F#, easy to hide its warts and build easy re-usable items.
But there's of course also smarter stuff with two-way bindings via html annotation and builders etc. I am actually using Feliz.ViewEngine, which is building the HTML using F#, but only for the navigation bar. Might try converting a page to it.
dotnet CLI should take care of build process, it can even generate self-sufficient executable (that bundle parts of .NET in them). The infamous required XML boilerplate has also been cut down to near-zero.
My biggest gripe is that Microsoft's debugger is closed-source and proprietary (though free for users of official VSCode builds). There is open-source netcoredbg by Samsung, so you can use VSCod[e,ium] with https://open-vsx.org/extension/muhammad-sammy/csharp , but YMMV.
F# also has an alternative toolchain based around Paket[0] and Fake[1]
[0]: https://fsprojects.github.io/Paket/index.html
[1]: https://fake.build/
Deleted Comment
editor: VSCode + ionide extension
stdlib: F# has its own stdlib but it can also access all of dotnet's stdlib seemlessly.
libs: Many of the 3rd party libs are written in C# in an OOP style but you can still use them. Most of the popluar ones have functional F# wrappers if you don't like OOP.
build: the dotnet cli is very advanced and not too hard to grok.
pkg: You can use nuget but most F# devs use paket
OPAM - despite the appearance of a modern language management tool - seems to fuck things up almost every time I use it. And not just me. The amount of time I was spending helping coworkers fight it got so much I gave up and just added a caching system so they wouldn't have to deal with the pain of OCaml at all.
So if F# manages to improve on that even slightly I'd say it's definitely worth switching to!
Plus it's more portable than OCaml, which seems to view working on the most popular desktop OS in the world as beneath it.
Deleted Comment
Like Kathleen says in her intro to f#6
https://youtu.be/jOrgDoMuFog?si=Dnu8kPPi5QS5rNOR
"Im gonna do cool stuff like fold this unfold that. Dom said. Why don't you just write code?" (Paraphrasing it's first of the video)
Like, the F# book that Brian Kernighan would write?
[1] https://www.manning.com/books/f-sharp-in-action
[2] https://pragprog.com/titles/swdddf/domain-modeling-made-func...
[3] https://fsharpforfunandprofit.com/
Thank you for your other recommendations, I’ve just ordered both books!
EDIT: Why the downvotes? It's just terse, it's not at all rude.