A new F# compiler feature: graph-based type-checking
devblogs.microsoft.com
devblogs.microsoft.com
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.
In theory Elm is just such a fascinating project... if it was not held back by the people developing it.
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.
I remember when the Elm team first decided to lock down the Elm compiler, so that only the team in charge had special privileged access to modify it. I thought, "wow, this looks like a bunch of people who don't want to collaborate, who want to take their ball and tell others how to play with it, really putting the 'dictator' in BDFL." and you know what? that's fine. I don't harbor anything against them as people. But that left a permanently bad taste in my mouth and I'm unlikely to ever trust that group or a project they're managing.
You're entitled to your opinion, of course, and you articulated it well. But again I see it as another example of someone not liking being told "no", no?
Obviously Elm is his passion project, that's fine. But nobody who locks down their compiler on a supposedly "open source" project can actually seriously expect others to engage with that in good faith.
Furthermore, the absolute state of just trying to modify Elm to be more fit for purpose is horrendous. Every time I see a parallel implementation or a fork, the author has to bend over backward with platitudes to placate the Elm masses and ensure them that this project isn't trying to "split the community," which is a nonsense idea to start with imo.
It feels cultish, on top of a project that is actively hostile to people who want to use it any way other than how the BDFL has mandated its usage. If you want to say the problem is with the users, that's fine, but that's exactly the attitude keeping me from ever engaging. I personally think the problem is with the people who want such fine control over their technology and community, as opposed to understanding that they can really only shepherd their implementation. That's about as far as their reach rightfully extends.
EDIT: also, the fact that they aggressively lock down their compiler and have such hostility to anyone working in parallel is imo the definition of "holding it back"
My complaint isn't that you or anyone doesn't engage with Elm, that's your prerogative, of course.
My problem is that a small segment of people do engage with it whenever it comes up to smear the project in general or Evan in particular for nothing worse than wanting to run his own project his own way.
He's not an ogre? I mean here he is, look, he semms nice enough to me? "The Economics of Programming Languages" by Evan Czaplicki (Strange Loop 2023) https://www.youtube.com/watch?v=XZ3w_jec1v8
What I usually see are warnings about what happened to the project and how it is run, mostly targeted to the unaware. This is a sign of respect to people's time before they waste it on something that might disappoint them when they get to know the details.
Look, I get it, I'm still sore about Google Feed Reader, 'member that?
But enough is enough. It's old news. Get over it. Etc.
It's like if every time someone mentioned Caddy server there was someone bringing up that time Matt Holt put that header in and pissed off a bunch of people. Life goes on. We forgive and let things go.
It's high time for folks to forgive Evan for his mistakes. I mean, he's very young still, eh? Cut the guy some slack already?
When I propose a tool to my CTO I couldn't care less about the project's leadership personal choices.
Mature engineers think in terms of ROI, dependability, bus factor, predictability, funding, mind-share, hiring ease, license, etc.
But it would be naive and unprofessional of me to handwave technical issues with the tools. And ALL tools have hard edges and undesirable characteristics.
And putting a header in a HTTP server is not proportional as restricting who can change the source code of a compiler.
Matt Holt is awesome btw. And so is Elm author.
I love the ELM Architecture. Why is there a problem if it is implemented in another language?
I'd think any functional language could implement the ELM Architecture, and thus be 'native', or more integrated into that particular languages ecosystem, and this would offer benefits beyond trying to integrate ELM into each individual ecosystem.
And doing this re-implementation, would in no way be a comment on the ELM founder.
Also, Doesn't Linus say "NO", quite a bit with Linux? Why jump on the ELM guy for doing same thing.
That's not what Elm does. They lock down the compiler so only Elm devs can modify internals, which would be equivalent to Linus trying to prevent people from modifying the kernel.
They really don't like people forking their repo, which would be equivalent to Linus getting mad at people making derivative kernels (because it would "split the community.")
It's not just a matter of saying "no," it's trying to control what devs do to an UNREASONABLE degree.
He is free to manage his project in whatever way he sees fit. And the public is free to criticize that management.
But that doesn't change the fact that calling it "character assassination" is hyperbolic.
As I go through rewrites and greenfield projects and so forth, I begin to realize that for any particular technology you are not simply having a relationship with a static list of pros and cons, but you're also having a living relationship with the team behind the work.
In other words, a bet on TypeScript is also a bet on the TypeScript team, and in my experience the TS team is very fast at their work. This makes me more forgiving of bugs. Similarly, a bet on Terraform is also a bet on Hashicorp.
Here we have someone recommending a choice of F# over Elm because betting on the leadership is allegedly not good. This is not character assassination. The commentator is not criticizing Evan on irrelevant private affairs and by extension saying that you shouldn't use Elm. Evan has created a company and is advocating for his product; he is a public figure and is being criticized on the grounds of project management.
Evan recently gave a talk about it on strange loop. https://www.youtube.com/watch?v=XZ3w_jec1v8
I would love Elm to be in a position where I could advocate for it at work (aside from it being a "neat hobby"). However, the simple fact is that the way Elm is run has lead to disillusionment among advocates of the first hour. And there is nothing to indicate that this will change.
And if the guy has inspired a new generation to create something to his own achievement, kudos to him. As far as I'm concerned Elm is not the enemy, JavaScript is the enemy.
* 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.
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.
For whatever reason, F# to me looks surprisingly verbose in Fable, which is odd because it's pretty terse on the backend.
For CLIs I much prefer self-contained build outputs which is quite huge when it comes to .NET unfortunately.
(mac, linux, windows, ios, android, web)
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/
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.
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
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...
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.
Warning: the question I ask comes from a part of my brain that is currently melted due to heavy thinking.
Context: I write a fair amount of Clojure, and in Lisps the code itself is a tree. Just like this F# parallel graph type-checker. In Lisps, one would use Macros to perform compile-time computation to accomplish something like this, I think.
More context: Idris2 allows for first class type-driven development, where the types are passed around and used to formally specify program behavior, even down to the value of a particular definition.
Given that this F# feature enables parallel analysis, wouldn't it make sense to do all of our development in a Lisp-like Trie structure where the types are simply part of the program itself, like in Idris2?
Also related, is this similar to how HVM works with their "Interaction nets"?
https://github.com/HigherOrderCO/HVM
I'm afraid I don't even understand what the difference between code, data, and types are anymore... it used to make sense, but these new languages have dissolved those boundaries in my mind, and I am not sure how to build it back up again.
Yeah, maybe, you for sure could, but in the context of F# as it exists, it may be hard to get from here to there.
> 'm afraid I don't even understand what the difference between code, data, and types are anymore... it used to make sense, but these new languages have dissolved those boundaries in my mind, and I am not sure how to build it back up again.
Yeah, good luck with that. I think maybe taking a mental step away from programing might help. It's true that human interpretation of the world often has these properties. And he generalization of the systems in no way invalidate the usefulness of the categorization system. Maybe it's helpfulnto consider the properties of your classes.
To risk your further descent into madness. I recommend the Lambda days talk on the Verse programming language [1]. Which has further contemplation on the topics you are thinking about. With an eye towards practicality.
What are you using as your development environment? Personally I don't find the overhead in Vim to be too onerous (`yypf"ci"NewFile.fs`), and even in Rider I routinely edit fsproj files manually. (I even create new projects mostly by hand.)
And other downfall. Do they still not work with DOTNET Core??
But this is also it’s greatest strength. Having direct, type-safe access to structured data is truly awesome. What else compares? Certainly not conventional code gen.
Java has what looks like SQLx on steroids with the manifold project coming down the pike.
https://github.com/manifold-systems/manifold/blob/master/man...
> How do Source Generators compare with Type Providers in F#?
> If you’re an F# programmer (or familiar with the language), then you might have heard of Type Providers. Source Generators were inspired in part by Type Providers, but there are several differences that make them distinct. The main difference is that Type Providers are a part of the F# language proper and emit types, properties, and methods in-memory based on an external source. Source Generators are a compiler feature that analyzes C# source code, optionally with other files, emits C# source code to include back into a compilation.
https://devblogs.microsoft.com/dotnet/introducing-c-source-g...
Edit: sample here with a JSON template: https://github.com/CharlieDigital/dn7-source-generators
> For Schema.NET, we do a HTTP request to get the JSON we need to build
https://turnerj.com/blog/the-pain-points-of-csharp-source-ge...
Also phillipcarter says yes so I'll happily take his view over mine.
Syntax is of course subjective but to my eyes it's cleaner in F#.
Idk. Don't want to start a war but rather hear specific arguments for why you like OCaml more.