The Early History of F# [pdf]
fsharp.org
fsharp.org
I use F# for anything critical and/or complex. It's a parsimonious way to represent domain models and a clear way to express computation.
My main regret with F# is that I didn't get into ML languages earlier in my career.
BTW a recent book, 'Stylish F#', is the best introduction to F# so far (no affiliation, just bought a lot of F# books over the years).
Incidentally 'Stylish F#' is intended to be an intermediate book so it might be worth reading Chris Smith's 'Programming F#' or one of the other intro books first - or some beginner online material. That said if you had C# exposure and were determined, you could probably get away with using 'Stylish F#' as your intro.
Functional languages allow logic to be expressed so precisely and concisely. I hazard a guess that every F# module is 2/3 the LOC of its C# equivalent, with the added advantage that everything is incorporated into a single file.
F# certainly has its quirks (as a language, I think Clojure is actually cleaner - but that comes with the downsides of the JVM and .NET interop is a huge advantage).
Part of me doesn't want to spread it around too much, because I feel like I've discovered some hidden edge over my hypothetical competitors.
There is a dotnet implementation of Clojure if you're interested: https://github.com/clojure/clojure-clr
F# feels like a secret weapon.
Why F# and not haskell?
F# has the power of .NET and its libraries behind it.
Haskell's insistence on purity and laziness does increase the time it takes to design things well. F# makes it easier to violate purity in controlled ways, and is not lazy be default.
People who've used both say it's a lot easier to get lost in abstractions with Haskell, and there doesn't appear to be a clear "stopping" point. A common statement by people who move from Haskell to OCaml/F# is "I spent N years on Haskell but didn't produce much. In 6 months of (OCaml|F#) I've produced more than in those N years with Haskell."
The bottom line: The .NET libraries and slight relaxing of purity/laziness allows for more productivity.
(I'm not an expert on either - just repeating what you normally find in the threads).
My position is this: different programming languages have different strengths and weaknesses. C++ is crazy fast, but it lacks many high-level features (most notably do-notation). Efficiency and performance are its niche. Conversely, F# (or any ML) is very good at expressing complex control flow, but performance is a secondary concern.
Package management is an IO-bound SAT problem, so we are using the best tools for the job.
[1] http://mlton.org/Performance
[2] http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.75....
Curious about your deployment happiness - are you bundling the runtime with your program? Last I checked, such a bundle was large (compared to a static c++ binary), and didn't have a nice single/few file(s) "container"?
Our development process is very pleasant. We use VS Code, .NET Core and Ionide as an IDE. I find an IDE essential for languages with global type-inference.
For bundling, we use Core RT to create a self-contained application. This is then bundled using Warp (https://github.com/dgiagio/warp) to generate a single binary.
The script is here https://github.com/LoopPerfect/buckaroo/blob/866ae97ffc82ab8...
The final binary size is quite reasonable:
- Linux 66.1 mb
- macOS 63.9 mb
- Windows 35.4 mb
I haven't investigated why Windows is so much smaller!
Ed: then again, your artifact is a build tool - does that build distribution packages?
Huh? I was sure I tested that after an announcement in... November? But it's supposed to have been supported a while longer? Eg: https://www.hanselman.com/blog/SelfcontainedNETCoreApplicati...
Perhaps a warp limitation?
F# tends to stick much more closely to its ML roots, and fairly scrupulously retains a more ML flavor except when necessary to achieve good interop with the .NET ecosystem.
Scala, on the other hand feels less to me like a dialect of ML and more like an ML-flavored object-oriented language, because it mixes in OOP-style features much more freely. Its algebraic data types, for example, are explicitly implemented as class clusters. A lot of people like this, others see it as an anti-feature. Where you fall probably depends on how you feel about the relative merits of OOP and FP.
It's also, for better or worse, less concerned with maintaining good interop with the rest of the ecosystem. Consuming F# modules from C# isn't always pretty, but it's always possible. There will be C#-friendly wrappers, but creating them is a matter of aesthetics rather than necessity. Consuming Scala modules from Java, though, frequently requires creating wrapper libraries. On the upside, this does mean that Scala gets to have things like typeclasses, which the F# team has kept out of the language due to concern about how they would impact interoperability with the rest of .NET.
Last but not least: F# has type providers. Scala has implicits. F# has quotations. Scala has more stuff that's also called implicits.
Any new engineer we get started with Scala has to spend about a week making their local setup work. It's a total pain in the arse.
1) The type system is focused on mathematical types as opposed to compiler tags. Mathematical types are about ensuring that a function will not fail. Compiler tags are about ensuring that you generate the correct asm op codes. Mathematical type systems allow you to have an easier time knowing the code works.
2) Algebraic data types provide both an AND component and an OR component. That is, you can do type X = A of int * int * int; AND you can do type X = A of int | B of char;. C# style languages provide you with the AND component (class A { public int B => ...; public int C => ...; }). However, they don't provide the OR component. You can create it by constructing weird type hierarchies, but this isn't idiomatic AND it also isn't closed. With an algebraic data type you can know that all of the cases are handled in a match. This isn't something you can ensure in C# (at least not naturally or easily).
Ultimately, I don't think functional programming provides anything that has to be better than object oriented programming. It's just that there are two facilities that tend to go with functional programming that allows a better way to model the problems that we encounter.
There are also many other significant differences. I estimate I am about ten times more productive in Haskell than Java.
So if you only have mutability inside of a function and it cannot escape, then you have no problems. Or if you have a way to prevent it from crossing module boundaries.
Rust for example, gives you some pretty good tools for controlling mutability and for tracking it. I think this is actually superior to a fully immutable system as with full immutability you end up with other weird problems (like needing monads and monad transformers to do things that would otherwise be simple).
I think one of the reasons that Rust doesn't have a traditional OO model is because you can't actually enforce mutability controls in that way. At the very least, when I tried to think of how I would find a way to enforce mutable and immutable data using java / c# style OO, I couldn't think of a way that wasn't kind of crazy or hard to use. On the other hand, structs with traits is actually pretty easy to enforce immutable data (hey, this requires a mutable borrow and what you have is an immutable borrow, so compile error).
I feel like we’ve taken the long way to popularize functional programming.
The most mind blowing variant was BETA, but I guess pattern based OOP was probably a bit too much for the common dev.
I really like F# pipelines and function declaration syntax.
On the other hand I've found Scala's case classes cleaner than F#'s (maybe that's because I am coming from an OOP world).
Additionally F# has a cleaner pattern matching compared to Scala.
Both languages have very good support for actor model concurrency (love akka actors and .net agents)
I think that if F# would have had a rich ecosystem the way Scala has, it could become a real contender.
(my 2 cents on F#)
That said F# and Scala aren't really competitors. The real competitors are the mainstream languages, like JavaScript, Java, C# and Python and that's what their marketing should target.
http://hackage.haskell.org/package/lens-4.17/docs/src/Contro...
This creates a bidirectional pattern synonym - you can both match and construct values with it:
foo :: Cons' s Char => s -> s
foo (a :< b) = 'c' :< b
foo other = other
Pattern synonyms make completeness checking undecidable so you need to give manual hints to get a nice api. It also wreaks cost models - is foo O(1) or O(n)?As it is, F# is like the cousin that doesn't always get the party invitations, while JavaScript, Python and C++ get the them, even if they don't belong to the club originally.
"Perhaps I am wrong, but let me state what I believe about this stuff. ...C# is not really important as it will never reach the 'mass' of VB..."
Which, yeah, proved to be hilariously wrong. Here we are in 2019, and I can still name several actively maintained applications that are written in VB6.
Another thing they couldn't have really known at the time was how exactly C# and .NET would evolve over the following decade. Once upon a time, interacting with COM interfaces was much easier in VB.NET than in C#, and that made it relatively more attractive as an enterprise dev language. C# 4 more-or-less closed that gap -- VB.NET's other practical advantages are so minor they don't really even bear mentioning.
Then they pivoted it into a managed runtime.
This would be a great primer for young developers to get a good overview of of programing paradigms and modern OS language evolution over the last 25 years. I will be sending this along to all my peers.
Also, I am impressed with .NET and Microsoft's embrace of OpenSource. I am one of those developers who got stung by Microsoft in their earlier days when they were the true Evilcorp and now they really seem to be less evil with this embrace.
I will actually consider using F# for my future projects, but of course as long as it runs 100% on *Nix platforms.
He also talks about F# history in a 2016 interview https://channel9.msdn.com/Shows/On-NET/Don-Syme-on-F