11 ms·
The Early History of F# [pdf]
- strangecasts 6y agoPublished as part of the History of Programming Languages (HOPL) IV proceedings[1], which also include articles about C++, D, Groovy, and JavaScript, and a few other languages. [1] https://dl.acm.org/toc/pacmpl/2020/4/HOPL https://dl.acm.org/toc/pacmpl/2020/4/HOPL
- chrisaycock 6y agoType providers were the biggest innovation I learned from F#. Type providers are a way to have static typing determined from an external source, like a CSV file or SQL database. I ended-up using a similar trick (with different syntax) in my own language, Empirical. I needed a way to infer a Dataframe from a file while in a REPL. It wasn't until I read the MSR paper that I realized I could do it entirely in the compiler without creating separate logic for the interactive users. https://dl.acm.org/doi/10.1145/2908080.2908115 https://dl.acm.org/doi/10.1145/2908080.2908115
- ridiculous_fish 6y agoWill you please share your insight? What are Type Providers? What is their advantage over, say, naively dumping type definitions from pre-processing a CSV file?
- tasogare 6y agohttps://docs.microsoft.com/en-us/dotnet/fsharp/tutorials/type-providers/ https://docs.microsoft.com/en-us/dotnet/fsharp/tutorials/typ... It’s not perfect though. When I tried to use them I ended up with problem so I parsed the data in more traditional way.
- chrisaycock 6y agoThe user could certainly dump a type definition, but for users who just want to point to some data in one go, the F# type provider[0] works with just: CsvProvider<"trades.csv">.Load("trades.csv") I personally didn't like having to list the file twice, so in Empirical[1] it's just: load$("trades.csv") My current version requires the dollar sign to tell the compiler that the parameter will be static (known at compile time). I'm planning on an updated version[2] that will eliminate the dollar from the function call: load("trades.csv") Basically, it means that users can just load the file like in a dynamically typed language, except that Empirical is statically typed. [0] https://fsharp.github.io/FSharp.Data/library/CsvProvider.html https://fsharp.github.io/FSharp.Data/library/CsvProvider.htm... [1] https://www.empirical-soft.com https://www.empirical-soft.com [2] https://github.com/empirical-soft/empirical-lang/issues/23 https://github.com/empirical-soft/empirical-lang/issues/23
- xvilka 6y agoThe original OCaml is more interesting. It has language flexibility F# lacks, gets new features every year, crossplatform, and compiles into the native code, thus faster. Once Multicore OCaml [1] project is finished the major painpoint of it will go away. [1] https://discuss.ocaml.org/t/multicore-ocaml-may-2020-update/5898 https://discuss.ocaml.org/t/multicore-ocaml-may-2020-update/...
- gameswithgo 6y agof# also has language flexibility that ocaml lacks. and ocaml isn’t always faster
- laylomo2 6y agoAlways love seeing a good rivalry between siblings.
- jolux 6y agoI love OCaml. F#, if you squint, is kind of philosophically like Clojure for the CLR: it leverages a heavily object-oriented but nonetheless very powerful runtime to allow developers to create strongly-typed functional programs that interoperate with a massive array of first- and third-party libraries that already exist. I wouldn't go so far as to say OCaml is more interesting. F# has things like computation expressions, async, units of measure, and type providers, none of which are trivial (or exist in OCaml), several of which are incredibly influential, and all of which are interesting. The long slog towards multicore for the OCaml community has been kind of embarrassing, with Haskell having offered arguably the best concurrent and parallel programming support in all of software development for years and years now. I will also note that F# gets new features fairly frequently as well, is cross-platform, and is extremely fast by virtue of running on the CLR, which I would not underestimate: https://benchmarksgame-team.pages.debian.net/benchmarksgame/fastest/fsharp.html https://benchmarksgame-team.pages.debian.net/benchmarksgame/... The features that it is missing from OCaml are admittedly pretty major, though. Row polymorphic records and the structurally typed object system are missed, not to mention rich modules and functors.
- algorithmsRcool 6y agoF# is the language that I keep coming back to. And as the paper notes, it has kept up well with the rapidly changing landscape of .NET Core and newer defacto standards introduced by modern C#.
- GiorgioG 6y agoIt had a very rocky start in the .NET Core world thanks to Microsoft's lack of interest in supporting F#. It lagged behind C# in significant ways and continues to get very few resources behind it.
- jackfoxy 6y agoActually Microsoft has quite a respectable team of developers dedicated to F#. It is true development suffered because the Roslyn compiler that MS invested a lot of effort into cannot be made to work for the language. F# has been made compatible with surrounding Roslyn tooling over time. (There is a distinction between the Roslyn compiler and the Roslyn tooling I am not qualified to explain.) The fact is that as a functional first language it does not require as much surrounding tooling as C#. Requirements for refactoring tooling, for instance, are far simpler.
- GiorgioG 6y ago> Requirements for refactoring tooling, for instance, are far simpler. If that's the case, it's sad that Visual Studio's refactorings for F# are so meager.
- algorithmsRcool 6y agoThis is another tragedy of the bifurcation of the F# and greater .NET community. Most of the investment in refactoring has been for Roslyn analyzers, which are C#/VB specific. F# has a completely difference compiler framework. I don't know if the F# compiler service or Roslyn came about first, but they are not compatible with each other.
- 6y ago
- dang 6y agoA draft was discussed last year: https://news.ycombinator.com/item?id=18874796 https://news.ycombinator.com/item?id=18874796
- bern4444 6y agoI've recently become interested in F# after I saw its use in a bunch of videos by Scott Walashin. I came across his talks, and subsequently his blog, as I'm getting more into functional programming and he has some awesome content. I use Javascript/Typescript professionally and I really like both of them. F# though has a minimalism in its design that is very appealing. Code I write in F# feels a lot less cluttered as opposed to the same function in Javascript/Typescript. This minimalism seems to be part of the language design with some following specific examples. - `let` is used to declare variables and functions. - The last statement in a function is implicitly the return value. - The type safety/mechanism is great and seems to be extremely similar to Typescript's so its easy to pick up for me (I'm not sure which came first or if there's a relationship but it certainly wouldn't surprise me). This along with some classic functional ideas that are built in like immutability by default, automatic currying of functions etc all allow for a language that seems be made to get out of the way. That's a very compelling idea for a language design to me that I previously haven't seen. Because functions and variables are both declared with let, perceiving functions as data kind of finally clicked for me since I first heard that concept 3 or so years ago. Another feature was to not require a semicolon as a line terminator and instead use it for another meaning as a separator. While JS doesn't require semicolons at the end of a line, its reserved for that purpose. Overall, I find F# to be a refreshing language (from javascript, python, java and even others like Rust or Go but I haven't used those as much so don't want to make bigger claims) and I'm glad to see a post like this on HN almost like validation of a community behind the language. I'd be curious to get a feel for some companies that actively use it as well. I also love that there's a compiler for F# to Javascript so I can use it to build front end code as I learn the language. Its pretty incredible we can do cross compilation of high level languages like this and with others like Rust and Go to wasm etc Edit: formatting of bullet points
- logicprog 6y agoWow this is a great comment about a new-to-FP viewpoint on F#. I came to it after I'd already experimented with Haskell and OCaml, used Rust a lot, and been programming with Lisps for years - and I was really impressed with it nevertheless! I really love the ML-family type systems. They're really great aides to programming, and makes planning really nice. F# has that, plus that usability from C# and TS. It's also, like you said, got a really beautiful syntax IMHO. I keep coming back to Rust though, because Rust is more general purpose, more performant, and applies better to the stuff I like to work on for my hobby projects. I'd love to use F# more but can't find a reason to at the moment. TypeScript, Python and Rust have become my comfort languages, but I like Rust the best, because it's got a lot of really nice features from ML languages and a powerful and safe type system.
- rurban 6y agoOh my so many warts. In haskell, ocaml but also F#. > Specifically, method constraints were added, introduced by a deliberately baroque syntax: let inline (+) (x: ^T) (y: ^U) : ^V = ((^T or ^U): (static member op_Addition : ^T * ^U -> ^V) (x, y)) > This definition says that any use of + is implemented via inlining a call to an appropriately-typed op_Addition method, defined on the type ˆT or ^U, i.e. the type of either the left-hand or right-hand argument. The ˆT notation for type variables indicates statically resolved type parameters (SRTP), i.e. type parameters which are resolved to a nominal type at compile-time. Why ^ and not using the existing : for seperating types from values? :T * :U -> :V would have looked like types, not pascal ptrs. Equally interesting are ocaml warts like let x2 = 1.0 +. 2.0 (+ not overloaded or defined for floats), or haskell's decision to torpedo the "class" keyword. Or ocaml hijacking :: let xs = 1 :: xs, with :: being cons, which was initially the lisp dot notation '(1 . xs) In retrospect perl's syntax is sane compared to this.
- Smaug123 6y agoYou're not actually supposed to use statically resolved type parameters. It's deliberately strange and difficult, because mere mortals are not supposed to use it. `::` is normal for cons in an ML, right? Of the ML family of languages, I'm only aware of Haskell that chooses differently (they use the single colon).
- smabie 6y agoI agree, though Haskell is certainly the most advanced. ML languages tend to be... primitive, at least to the modern eye. The lack of function polymorphism in OCaml is such a huge bummer. Modular implicits have been proposed (in a paper from 2014), but it doesn't seem that they are being actively worked on. If I could get multicore and modular implicits, OCaml would be the ideal language.
- octachron 6y agoModular implicits are being worked on actively, it is just a hard feature to get right in a scalable and future-compatible way.
- tejasv 6y agoWe, at Chaldal (YC S15, chaldal.tech), use F# in production. Most of our backend projects are in F#, the last one is being migrated over slowly from C#. Our new frontend projects are also in F# (using Fable). I want to share some insights of using F# with the community. We started from a C# codebase, and realized that a better language can help weed out most bugs in our system. And yes, it works. Pretty much all bugs we face these days are parts where the F# world touches something non-F#, like .NET and other libraries written for C#, where interaction (like nulls) is not well-defined. We've taken Scott Wlaschin's (fsharpforfunandprofit.com) teachings to heart, and we have a giant banner in our office that reads "Make illegal states unrepresentable". It took a bit of learning for everyone to jump in, but our dev team has loved the experience as the language is a pleasure to use; when they need to go back to write C# or TypeScript code, a lot of these learnings transfer. People just become better programmers (as is true with learning any functional language). To get all the benefits of F#, you must adopt the whole paradigm. While F# allows C#-like OOP, and while this can be an initial stepping stone in the path towards F#, you must go all the way. If you simply do OOP, the trade-offs aren't worth it, IMO, as F# is a functional-first language, and the OOP is mostly provided for interop with the rest of .NET. IDE support has been janky in the past, but its improving. Latest VS 2019 is pretty good, and JetBrains Rider works pretty well on the Mac.
- throwaway_pdp09 6y agoI get the "Make illegal states unrepresentable" in theory but how do you do it actually for nontrivial preconditions like "this list must be sorted"? (as a precond for a binary search on a vector, for example). OOP is fine with functional if you make it immutable too, so I don't see the problem (I've not really got a problem with mutable OOP, or state generally, if it's done carefully).
- choeger 6y ago> how do you do it actually for nontrivial preconditions like "this list must be sorted"? This depends on your data model, of course. But for a list of integers you could do the following: 1. Have a unique data type that is the list of Deltas, plus the initial element (So for instance the list [5, 3, 6] would be encoded as (3, [2, 1]). 2. Provide a sort function that creates such a sorted list. 3. Make the sorted list your input parameter. This is obviously oversimplified, but I hope you get the idea. A cheaper alternative is to 1. Make an opaque datatype "sorted list", together with a function that translates this type to a normal list. Implemen this type just as a list, but keep the implementation private. 2. Provide a function sort, that is the only function that can yield that type. 3. Demand that type as input.
- addictedcs 6y agoThere are a couple of concepts in F# that I really like: * actor-based approach to concurrency[1]. Very useful when you want to design your code lock-free. Treating instances as agents that read messages from a mailbox, frees the developer from using low-level threading primitives. First time I've used this approach in production with AKKA and Scala. In F# it is much cleaner because the language itself is built on a better platform. * exhaustive pattern matching[2]. Writing in F# means using pattern matching a lot. Exhaustive matching gives you the confidence to refactor and maintain your code. The compiler will warn you when adding a new value in your type and not covering the execution path that uses it. It catches a lot of errors before you even push the changes to CI. * obviously immutability, conciseness, currying, these have been mentioned so far by others. One nitpick in F# are Exceptions [3]. They approached it similarly to how it is done in C#. You are allowed to define and throw an exception that will "jump" somewhere in the execution path. I prefer when a method returns Option-style types. This way, you know what to expect from a call, and pattern matches on the result without adding one more execution path in your code, which covers exceptions separately. It was added to support C# style error handling, though I very much prefer an error-code-based approach. [1] https://fsharpforfunandprofit.com/posts/concurrency-actor-model https://fsharpforfunandprofit.com/posts/concurrency-actor-mo... [2] https://fsharpforfunandprofit.com/posts/correctness-exhaustive-pattern-matching https://fsharpforfunandprofit.com/posts/correctness-exhausti... [3] https://fsharpforfunandprofit.com/posts/exceptions/ https://fsharpforfunandprofit.com/posts/exceptions/
- lihaoyi 6y agoI have a special place in my heart for F#. While I do a lot of Scala these days, professionally and open source, F# was my first introduction to functional programming that eventually got me into Scala. F# and Scala are extremely similar languages: garbage collected, hybrid OO/FP guest languages hosted on a widely-used runtime. Even though the superficial syntax is very different, and the advanced language features they provide are pretty different, the core experience of modelling your data as "dumb" data structures and transforming collections of data using higher-order functions is almost identical. Scala ended up winning out for me due to a broader ecosystem (Much more OSS Java than OSS C# out there), better tooling (Visual Studio's F# support was always disappointing...), and easier interop (F# <-> C# feels a lot more clunky than Scala <-> Java). But I can easily imagine an alternate universe where I'm happily writing F# all day, and almost nothing would be different from my current work writing Scala.