I'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
Scott's talks about F# are exceptional, and quite compelling for "line of business" developers (as opposed to language enthusiasts) - something functional programming advocacy often misses in my opinion. This is also something that his site (https://fsharpforfunandprofit.com) does a good job of.
On a slight tangent, you might enjoy the slides from Scott on a different topic - model checking with TLA+ - from NDC Oslo this week:
Oh that's awesome. I first came across TLA+ (probably also through HN) about 6 months ago and recognized Leslie Lamport's name. The concept was very interesting but I had trouble getting to a good enough understanding of TLA+ to be able to use it. I'll look to see if I can find the associated NDC talk on youtube but his slides are also great. Thanks for sharing.
He does an incredible job conveying the ideas and intuition behind a lot of the terms and concepts for a given subject.
OCaml also has a compiler to JavaScript - BuckleScript[1]. There is also js_of_ocaml[2], jsoo in short. Though I personally hope they will go with the WebAssembly route[3] and support it in the mainstream compiler out of the box.
Wow 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.
We use F# to build fairly complex portfolio management apps. It's a great match for F# to Javascript transpilers (Fable, WebSharper). It makes it easy to share functions and types between UI and backend and to have powerful type safety. I.e. you change your DB data type and compiler informs you where in the UI you need to make appropriate changes.
This works great with "makes illegal states unrepresentable" approach. It helps to reduce a need for boring unit tests and lets you focus more on expressing domain in code directly.
I love this idea too. Is it possible to create a type (in F# or Typescript) to represent an idea like greaterThan2? A value whose type is greaterThan2 would have the obvious constraint the value is always bigger than 2. Having the compiler check such a condition would be awesome.
I kind of can do it for Strings by doing something like this
type ValidStrings = 'name' | age | 'dob';
The easy way around this is a function to determine this
function greaterThan2(num) return num > 2;
but it'd be cool to express this level of dynamism as a type.
As others mentioned - using smart constructor technique, but not directly as F# has no dependend type capability.
Smart constructor technique works well with 'parse, don't validate' approach [0]. You can push type construction to the boundries of your system so that you can work on a domain code with more precise types. It's not always so rosy however as too much types can become a burden.
This is called dependent typing, and F# doesn't have it as far as I know. There are other ML-family languages that are capable of it however: Liquid Haskell and Idris are the two I can recall off the top of my head.
in F#, yes, in TypeScript, not really. The technique involves using a combo of an opaque nominal type, and a smart constructor:
(* GreaterThanTwo.fsi *)
type t
val make : int -> t option
val to_int : t -> int
(* GreaterThanTwo.fs *)
type t = Value of int
let make int = if int > 2 then Some (Value int) else None
let to_int (Value int) = int
Now, `GreaterThanTwo.make x` gives you a value of type `GreaterThanTwo.t option`, meaning it can be `Some` value or `None`. If it's `Some` value, that means it really does contain an int greater than two and you can get that int using `GreaterThanTwo.to_int`.
This is so true. It's why I love ML-languages: they help me refactor, the help me logically structure my core (through its data types) even before I start, and it helps catch illegal states (if I use the types right) so that unit tests aren't necessary!
High praise and interesting to hear this as well from someone else. I feel like I'm on the right track with my analysis in my main comment.
I saw in a different HN post a few weeks ago that jet.com heavily used F# but obviously that's no more.
If a company were using F# and I were looking to switch and all the other stuff was a good match, the language choice would be a big pull for me.
While I use and am learning F# for a side project, there's no substitute for working with one professionally and shipping production code with it. I wish it'd be possible to convince my engineering group to use it.
If your engineering group already uses C# then it might not be such a difficult sell - the two languages are highly interoperable, so you may be able to carve out a particular greenfield project and write it in F# instead of C#. Note, though, that we've found it necessary on project `FooBar` to create specific `FooBar.CSharp` wrapper libraries that C# users can consume; this is because idiomatic API design looks pretty different between F# and C#.
(If you're interested in quant finance in London, I work at G-Research which uses F#; I write almost solely in F# there. You can contact me privately if you like at patrick+gresearch@patrickstevens.co.uk.)
Rust is actually the one other language I'm interested in learning now and is on my list. I have a feeling I'll be in a similar mindset to you once I learn and get some experience with it. I'm interested to compare its syntax to F# as well since to me the F# syntax and design is what I find most compelling.
More broadly there seems to be a big push for updated (perhaps even modern) versions of established languages and I think this is an incredible development to witness.
Rust, Go, Typescript, Scala, Kotlin are all the rage and seem to replace C/C++, javascript, and java. Others might exist for either side as well, this is just off the top of my head. From what I see and read as well functional programming seems to be a lot more popular and a lot of these languages are either built for it or with a good base of support for it. It'd be really interesting to have some hard data to know if this is accurate or just my perception.
My only other exposure to functional programming was an undergrad class required for a CS major (thank gosh it was a requirement too). It used Scheme for the language and Structure and Interpretation of Computer programs for the text book[1]. Looking back, this was the most useful class I took and the ideas have stuck and continue to inform me today. Its the one text book I've gone back to on occasion just to take a look and I've found some versions of it for JS and F# even on github which I use to help learn the language or review the concepts in languages I'm more familiar with.
I need to give F# a try. Really love the ML style type systems as well, I've played around quite a bit with SML and OCaml, and have been using Rust as my "daily driver" for almost 3 years. Rust definitely feels like the most practical of the MLs
There is a lot to like about F#, but I honestly prefer Typescript.
I feel like it really has hit the sweet spot between FP and OOP. And while I do tend to prefer the more terse ML syntax of F#, Typescript is pretty close and, frankly, offers a more ergonomic experience in your editor (F# syntax highlighting in every editor I have used is woefully underwhelming).
Add to the above the structural typing vs nominal and Typescript really does offer an immensely rich and flexible paradigm. The only feature I'd really like to see better support for in Typescript is currying/partial application These can be approximated in TS using it's incredibly powerful type system (dependent types using "extends" combined with inference using "infer"), but newer versions will throw an exception when the compiler sees an infinitely recursive type.
re: relationship to TypeScript, I'm interested in which parts seem similar between the two to you. TypeScript is primarily structurally typed while F# is primarily nominal.
Sure thing, I'm still pretty new at F# but have a good handle on Typescript since I get to use it at work.
The three main things I find similar are the syntax, ability to compose new types from other types, and the ability to limit types to certain options. Both support | as an OR and support an AND operation. F# does a bit more allowing the product of types though.
Syntax Example:
Typescript
---------------
type Check = {
amount: number;
account: number;
...
}
F#
--------------
type Check = {
account: int;
amount: int
}
I think I need to become a bit more familiar though with F# to understand the differences better. I hadn't yet heard the term nominal to describe a type system before so I'll look into it further. Perhaps I'm focusing more on the syntax than is warranted...
Completely separately, how does one properly format on HN? Is it possible? Is there a doc somewhere? I'm fairly new to commenting...
Your example is actually a really good one for discussing these differences, and the syntax is indeed similar. That TypeScript code is introducing a "type alias," which is a special name for another type, rather than a new type of itself. (https://www.typescriptlang.org/docs/handbook/advanced-types....)
This is a concept that F# does not have, because F# doesn't support structural typing. In TypeScript, you could just as well specify that a function returns
{
amount: number;
account: number;
}
directly, and it would be equally compatible with anything expecting a "Check," because Check is just a shorthand for that object type. I can't easily declare that a function accepts { account: int; amount: int; } in F#, I have to declare that it accepts "Check." That is the main difference between TS and F# here, and incidentally also the most basic difference between structural and nominal type systems.
I'm not sure why the syntax is similar though, F#'s is based on OCaml's record syntax while TypeScript's is really just a JavaScript object literal but with semicolons instead of commas. I believe it supports commas too. It may be genuine coincidence, or the designers of TS may know of the ML family, which is highly influential among language designers and implementers.
You can use it like an interface, and accept loadReceipt functions for anyone who needs to load receipts... Then partially apply a SQL version, noSQL version etc.
Thanks for the formatting link, exactly what I was looking for to format code a bit better.
That actually helps me understand some F# code I wrote last weekend as well regarding construction of objects of a certain type...
I didn't know about the difference between nominal vs structural types but your explanataion makes sense. It's the subtle distinction between a type vs a type alias that you pointed out.
I personally use type aliases in typescript over interfaces, I think they're a more natural fit for JS than interfaces but that's a separate conversation :)
Language design is really interesting especially the choices designers make. I feel like they must all pull at least in part from each other and would be curious to explore any relationships but if its total coincidence that's pretty incredible too.
> I personally use type aliases in typescript over interfaces, I think they're a more natural fit for JS than interfaces but that's a separate conversation :)
The TypeScript docs recommend the opposite, preferring interfaces. Interfaces are also structurally typed in TypeScript though; the major differences are that interfaces can only be used to declare object types: https://microsoft.github.io/TypeScript-New-Handbook/everythi...
The fact that interfaces are limited to typing objects but type aliases can also be used for functions is an easy +1 to type aliases.
My view is that declaration merging is a bit of an anti pattern that could cause trouble if two different people write an interface with the same name but to represent different data... now they get merged incorrectly. A type alias forces more explicit behavior where composition must be done by creating a new type alias as the union of two or more other types
I think it’s a +1 to using both depending on where they fit. I use type aliases for defining unions and intersections and such and interfaces for everything else, personally.
And that’s an intersection you’re describing there, not a union. Interfaces are explicit about extension as well, they use the “extends” keyword.
Whoops, yes that is indeed a union not an intersection. Thanks for the correction. I'm still getting used to the terminology.
The explicitness I was referencing is around the declaration merging. Its automatic so unless there's a conflict between two interfaces with the same name but with different properties, a dev wouldn't know that it was being done.
I agree with using what makes sense for the scenario. I prefer type aliases for functions and interfaces for classes and that seems to work out pretty well so far.
You can do anonymous records in F# - you don't have to explicitly give a name to your record types - but structural typing solves similar problems to those solved by interfaces, and F# thoroughly supports interfaces, so I imagine it wasn't thought necessary to make the type system any more structural.
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