F# is gaining independence from .NET
onurgumus.github.io
onurgumus.github.io
I want to provide a little nuance around this, because I'd give the opposite advice.
Because F# is based on OCAML and an extremely popular IDE/framework, it is first and foremost a teaching language. In my opinion, for what it's worth, the biggest mistake other F# coders make is running off into Haskell-land and trying to drag the rest of the community with them. Yes, pure FP is love and goodness, joy and love, but that's not the place to start with your average coder who just wants to see what's cool. Fable and Elmish are
I learned functional programming by reading a lot of OCAML books and the only(!) F# book out at the time. I coded like shit. I couldn't help it; I came from a strong OO background.
But then I figured out that instead of coding everything perfectly, it was more important to finish a little bit at a time, then take a look at functional smells, things like mutation. Sometimes I could fix these smells, sometimes I couldn't. Over time I found I could fix all of them. At that point I was a functional programmer.
I love these high-level F# frameworks, and like I said it's the best way to get folks involved, but wow, folks are going to create some programming disasters using them. Yes, this happens all the time withe every new thing, but functional messes are an order-of-magnitude worse than imperative/OO ones. Good luck, guys! The destination is worth the journey.
I find them an order of magnitude easier and safer to refactor. And I have done it a few times with production messes I was not familiar with. Immutable values instead of variables and idempotent functions (those not having side effects) makes refactoring a joy and the if it builds it works mantra is pretty much true.
Where things can get weird is when you start passing partially applied functions to other functions, and then you use type inference on function signatures on top of that. Glancing at the function signature its completely opaque what is going on. Hopefully you aren't in github and have working code lens and then you get a type signature to help, but it gets very verbose and confusing, and is still hard to reason about, for me anyway.
A thing I find helpful with F#, no matter what style you use, is always type out the types in function signatures. Yes this has downsides occasionally when a refactor might have just worked without adjusting types through a chain of functions, but I think it is a net win for productivity.
The signature never lies. Although I intellectually understood this early on, sometimes when I was in the throws of not understanding code my mind would not understand the signature or somehow would not grasp the important information it was telling me.
When they get a little complex and include generics they can get difficult for humans to parse.
The signature is truth. Stare at it, struggle with it until you get it.
One of the things that attracted me to F# is that every page of code is much more information dense than any language I had previously worked with. While I consider this good, it can also be daunting.
Terrific insight. So important.
As a Java partisan, I can say without reservation that Java is a suboptimal teaching language. So I easily believe your assessment of Haskell.
> I couldn't help it; I came from a strong OO background.
My functional eureka moment was deleting an element from a list using recursion. It literally changed how I see the world.
I haven't done any functional programming in anger (for pay) in a long time. But FP absolutely has informed, influenced all that I do.
Teaching multiple paradigms and styles is so important.
Why so?
There's nothing wrong with any of that. As a professional, you want to be good in multiple paradigms. The problem is that you're mixing them all up, whether you realize it or not (Most of the time, programmers don't realize it) And now, every piece of code can go down two entirely separate tracks as you suss out your architecture. Not only is that not going to work, it's going to make debugging and maintenance a nightmare.
This is very, very similar to how good C++ shops work. You've got to tightly limit the way you solve problems in order for all of the programmers involved to be to reason about the code.
F# code, from my somewhat limited experience, seems to almost always be organized logically (top to bottom, types separated from functions) using well-established patterns. Obviously if you decide to write a bunch of classes and mutating code in F# when more idiomatic approaches would work, it’s going to get hairy.
I feel like I’m missing your point.
That is just a curried function with three arguments. The bigger problem is that programmers still have to understand how Hindley-Milner type inference works to figure out type errors. This gets worse when you add in type classes, dependent types and (Yog-Sothoth help you) lenses.
Your point is still true. For any language, it is important to have an IDE ecosystem in place. The tooling must enable developers to move beyond fighting the unruly or boring parts of the language and instead leverage it to work on the domain.
let createMemoizer f =
let cache = Dictionary<_,_>()
let f' = fun x ->
match cache.TryGetValue(x) with
| (true,value) -> value
| (false, _) ->
let result = f x
do cache.[x] <- result
result
f'
The signature is ```createMemoizer (f:'a->'b) -> 'a->'b```, which is not very telling, especially if it is returned by yet another function, so that even the createMemoizer name is lost. In classic OO, I'd just get a Memoizer object that carries vital documenation and what not with itself, as it is passed around. It's no even that much longer, it's just not as elegant to use. class Memoizer<TINPUT,TOUTPUT> {
Dictionary<T,TOUTPUT> cache = new Dictionary<T,TOUTPUT>();
Func<TINPUT,TOUTPUT> f;
/* ... */
public TOUTPUT Invoke(TINPUT parameter) {
if (!cache.TryGetValue(parameter, out var result)) {
result = f(parameter);
cache[parameter] = result;
}
return result;
}
}I think the ergonomics of a high degree of functional programming haven't panned out to be real crowd pleasers just yet, so you're not alone in thinking that.
[1;2;3;4] |> List.map ((*) 2) |> List.reduce (+)
Also, this is another pet peeve about 'functional style' F#, the use of actual Linked Lists, which is a huge performance pitfall to accept on modern hardware.
And also that F# Seq are not well optimized.
That example without pipes is
List.reduce (+) (List.map ((*) 2) [1;2;3;4])
Linked lists are common in any functional programming language, the performance is bad but that only matters if you're writing something performance-critical. Otherwise, the ergonomics dominate: lists are very easy to work with.The ergonomics of LinkedLists really aren't any different than could be achieved with an array backed List, it just isn't done. I realize part of that is because it facilities immutable data structures, but they are often used when that isn't happening.
It still isn't as simple in implementation as a linked list, but they really shouldn't be used except as immutable data structures. That's the only reason I use them.
Phillip mentions this below but F#'s Seq does not add overhead to IEnumerable, it is exactly the same as IEnumerable.
I'm curious about what you see as the unavoidable overhead in IEnumerables, though.
The one bad thing about it is that the documentation is really insufficient and confusing to people who don't already know .NET. If this improves it will definitely be welcome be more devs and companies.
If you look at the MS documentation for .net, none of the examples are in F#. I guess that's okay since it probably wouldn't be idiomatic F#... but still, the docs have examples in C#, VBA, and one other language (I think it might be C) but no examples in F#.
The docs are bad but not inexcusably so, it's a nice project within MS, I get it. The underlying machinery leaks a little into the language, things like "discard" are irritating but not unforgivable. And it's not just running native, I know NET nerds will want to tell me about corert or native or whatever it's called, but that doesn't solve the issue. F# has a weak core, it's not like Clojure where I have this wide array to choose from regardless of the platform. I can choose NET or Fable and the development experience varies wildly between those two environments, in my limited experience.
All in all, I think F# will live a medium-length life. Without solving the native problem and moving beyond NET, I don't see it flourishing in many important niches.
If I was going to adopt a new language, it'd probably be Nim over F#, etc.
You can write C bindings for F# libraries compiled this way.
Same hello-world console app from C# runs alright with AOT. The F# does not as it relies on heavier reflection stuffs (at least thats what it seems like). The F# version did compile but just crashed on run.
The suspect appears to be the way to console print seems to call a different non AOT function.
The interesting part was I did write some bindings calling for a console print via CFFI that did then allow me to compile the F# app and run fine.
https://github.com/dotnet/corert/issues/5780#issuecomment-40...
For frontend dev't I really like Elm lately. (the article makes many refs to Elmish, the Elm-on-F# project).
Beyond different OOP mechanisms, some things OCaml has that F# doesn't:
- Functors
- Polymorphic variants
- camlp4
And some things F# has that OCaml doesn't: - Computation expressions
- Type providers
- Quotations (as a built-in)
- Units of measure
- Active patternsKinda yes, kinda no. There's a whole interesting story to it:
I am glad that Elm has influenced so many ecosystems. I wouldn't touch it with a ten foot pole because of the author, but I think the ideas of the project are invaluable and long overdue.
I think Fable wins over Elm, simply because F# is such a great server-side language. Even if I was writing an Elm app, I would still likely reach for F# on the back-end.
Here's a good starting place. Look for some discussions about typeclasses and read for yourself. Ask yourself if you'd bet on this person, and if you'd build critical tools for your org with a tool dictated by them.
I have no ill will for Elm. I'm grateful it exists and that we can all learn. I'd never invest in it though, it's too much a risk for things that could affect my ability to put food on the table quickly enough.
I'm not a frontend guy, so if some crazy frontend bug happened and crunched up my landing page or any of my forms, I'm not confident that I could debug it fast. I hate to say it, but honestly I think TS has to be the future of front end web. It's simply too solid to consider very many other options.
The one-man-running-the-show act kinda works for small things, like Tarsnap is a great example. But for languages that are powering business frontends, I can't have some goofball with a bad opinion holding up progress on something important.
The syntax is also way nicer. Having to type out "implements/extends" instead of ":", for example. These goes a long way to denoise a very noisy language.
C# was developed independently of J++ and J# (though J# was based on J++ to provide a transition path for J++ developers), and although Anders Hejlsberg (original lead architect of C#) did also work on J++, he also worked on Turbo Pascal and Delphi before coming to Microsoft, and I'd suspect that those influenced C# more (more conceptually than syntactically, of course).
In fact, having had spent most of my focus across Java, .NET and C++ since their early days, it is quite interesting to follow how certain features keep being copied across them.
In fact, Kotlin/Native is a poster child example of how not to design a language breaking the memory semantics with the rest of the eco-system.
https://itnext.io/why-the-kotlin-native-memory-model-cannot-...
Naturally this wasn't going to turn out well, and now they are redoing it with a proper GC.
https://blog.jetbrains.com/kotlin/2020/07/kotlin-native-memo...
The .net, python and JVM contain some of the largest ecosystems. Even if small relative to C#, the niche size and health of a functional language on .NET is much larger than if it were another native langauge. Speed, documentation and tooling might not exactly match C#, but are excellent in comparison to other functional languages.
In a similar vein, niche size for a transpiled functional language is much larger, more so if the language prioritizes playing well with its parent ecosystem. There is room enough for Fable, Clojurescript, elm, purescript and Reason to co-exist.
Meanwhile state of the art JITs (for .NET, JVM, Swift, and other traditionally managed runtimes) are increasingly blurring what it means for a language to be native and what the benefits for "native" even are.
So I don't think it's useful to think in terms of niches, because niches are constantly disappearing within our ecosystems. We're reaching a point where the implementation of a language is mostly a solved problem (throw it on top of some JIT for a bigger language) and the only meaningful innovation is in the semantics and syntax of a language for expressing intent and providing soundness.
If we're skating to where the puck is going here, I wouldn't say it makes sense to ignore native compilation for functional languages because that's a well served niche, but because AOT compilation itself is becoming niche.
Fable is a game changer and is arguably a better Typescript in terms of jacking into the javascript ecosystem.
Ruby had Rails, Python had Django + Pandas.....
F# has Fable
Don Syme has a great talk about this, but essentially things get out of hand very very quickly.
https://youtu.be/1AZA1zoP-II?t=2408
With Fable you are able to take the simplicity and conciseness of F# and jack into the entire JS ecosystem without falling into the type hierarchy nonsense.
Frustrating when I just want to play around.
Should be a bit easier!
Gah lots to learn.
F# tooling (e.g IDE support) is infuriatingly not as good as C#. Yet at the same time, the tooling is pretty decent, especially for a functional language.
Its made on top of monogame and should have a battle tested core. But the lack of knowledge/adoption for Xelmish is disappointing.
What is the point of the Elm architecture?
I cannot figure out why the `model`, `view`, `update` architecture is preferable to its OOP counterpart. That is, simply defining an interface for each of the above where `IView` and `IUpdate` each contain a single method with the appropriate parameters. That is objectively[0] cleaner!
The current recommendation is to create these ungodly unions for handling the view/update logic. It feels ridiculous and really starts to gum up your modules with implementation logic that is _entirely_ unrelated.
FP and OOP each provide different (opposite) faculties when dealing with the expression problem. FP says[1], "I want to optimize for adding new _behavior_ to the same pieces of data" (one can add functions that operate on the same data without needing to recompile). OOP says[2], "I want to optimize for adding new _data_ with the same kinds of behavior" (one can add classes encapsulating different data that have the same operations without needing to recompile). How does the above square with an architecture built around a set of _single_ functions that operate on different (changing) pieces of data?
The Elm architecture seems to have chosen the exact wrong paradigm (and its associated semantics) for optimizing change! You aren't adding behavior as you build out your application in this architecture. You are adding _data_! The "behavior" is defined exactly one time (in the signatures of the `view` and `update` functions) and doesn't change. I must be missing something... is this really just so we can say "the complier will let us know if we forgot to handle a case"? That seems like a pretty hefty trade-off if you ask me. F# has this beautiful multi-paradigm capability and, in this case, it's been woefully ignored.
[0] Okay fine maybe not objectively, but it certainly seems preferable to modularize this logic.
[1][2] I get it. They don't actually say anything, but the general approach to the EP remains true for most cases.
So you see these two goals are contradictory. How FP tackles this state problem? One solution is to use actors and agents. And that's precisely what elmish is. Unlike the conventional apps where you mutate the state directly, an agent in F# is a recursive call which can await for further messages.
So just like Flip Flop holds the state in memory, an agent hold the state in a recursive function. And how is this connected to elmish? Let's see how elmish v2 is implemented: https://github.com/elmish/elmish/blob/5330f52153d5181923bb3c... You can see an agent there and that's the core of elmish.
So basically elm and elmish is a way to handle state changes in a functional manner along with side effect support via commands.
I cannot emphasis importance of elmish, because not only it helps for isolating the state functionally but it helps you to keep your business logic separate from UI. So you don't end up messing your code like you use React hooks or context.
If the framework only expects every `Model` to contain 2 methods (`view`, `update`) and never any more (which is the case), I see no reason at all to adopt the Elm architecture. The interface for `update/view/model` is well-defined and un-changing. It's clearly sitting on the wrong side of the expression problem.
The program loop could work exactly the same no? Just re-organize:
let (model',cmd') = program.update msg state
to: let (model', cmd') = state.update msg // I'm not sure where/how program fits in
My question is truly as simple as trying to figure out the advantage of the chosen semantics (in F# - I don't know Elm). It can't possibly just be "because we want to stay on the Functional programming realm" can it? Immutability can be achieved in any paradigm. Forgive me if I am coming off overly controversial - I don't mean to be.https://guide.elm-lang.org/webapps/structure.html - Even here in the "MVC" section the documentation _recommends_ you organize your project according to type (containing the `view` and `update` functions). This is very-much akin to my critique. If you reach the point in your project above you have essentially regressed back to OOP (in FP clothes).
In order to write that you have to pin a reference to the state. But state is something that has to flow. Sure you can pin it to a ref, make it mutable and change the state but then nothing prevents you to change the state arbitrarily e.g. from a command. I believe yes the answer is because we want to stay on the FP realm. FP imposes some restrictions to keep our sanity. So not having a reference to the state and making it immutable is one of those restrictions.
Forgive my ignorance, but why is that the case? Isn't `state` being passed into the loop?
Mutability is orthogonal to the question of where one defines a unit of behavior. Maybe an immutable object is not possible to achieve in F#, but one could certainly imagine the concept of an immutable type with methods. My question is more about the modes of organization: Large unions vs discrete modules and how they affect how one's ability to change a program over time.
If you say that the architecture was chosen out of a purest sense of FP, then fair enough. I can understand why someone would go that route. Just had to know.
The problem (truly the problem) is about _where_ one defines behavior. It's the expression problem (EP) at its core. A FP approach separates data and behavior in a way that makes adding new behaviors to the same data types easy and OOP combines them in a way to make adding new data types to the same behaviors easy. It's literally the difference between:
let model' = update model msg
and: let model' = model.update msg
Like I said, I don't know Haskell very well (and had a hard time grokking the link), but any purely functional language will suffer from the former over the latter. The side of the EP a language falls on is simply as a matter of the data types/type system available.Compared to Swift F# has excellent documentation.
Would be interesting to know what F# is compared with in this case.
Is there a language thats known for excellent docs ?
One thing you can’t pass on when talking about fsharp in the community.
If you have a question just ask on twitter or slack. You’ll get an answer in minutes.
Elixir.
Main docs: https://hexdocs.pm/elixir/Kernel.html
Here's a (3rd party) library's docs. I recommend also checking out "guides" in the upper left corner: https://hexdocs.pm/oban/Oban.html
In my experience the Rust docs are great, there's a good mix of types as documentation, high level explanations and examples, with easy access to the source code. Here's an example with the HashMap [1]. There's also the Rust Book [2], which is great because it provides beginners with somewhere to start (F# seems to currently lack this).
The situation is pretty much the same with Elixir, great docs [3] and something to get people started [4].
[1]: https://doc.rust-lang.org/std/collections/struct.HashMap.htm...
[2]: https://doc.rust-lang.org/book/
[3]: https://hexdocs.pm/elixir/List.html
[4]: https://elixir-lang.org/getting-started/introduction.html
Mathematica's documentation is extremely good (reference.wolfram.com).
They're pretty good for PHP + Rust.
I didn’t quite understand this section and it seems very counterintuitive can someone elaborate a little?
I wish languages didn't insist on preserving quirks like this one.
Evil dangerous code using global variables:
let mail = // .. create email service
let db = // .. create database service
let receiveThing thing = async {
let query = // .. compose update query
do! saveToDb db query
let emailText = // .. compose email
do! sendMail mail emailText
}
while readInput() do receiveThing (getThing())
Beautiful pure code using dependency injection: let mail = // .. create email service
let db = // .. create database service
let receiveThing db mail thing = async {
let query = // .. compose update query
do! saveToDb db query
let emailText = // .. compose email
do! sendMail mail emailText
}
while readInput() do receiveThing db mail (getThing())
[1] https://fsharpforfunandprofit.com/posts/dependencies/What F#'s aversion to cyclic dependencies does forces you to break cycles of types referring to types referring to types. The way you do that is by writing a generic function that avoids referring to a concrete type. Because it's generic, such a function is inherently easier to test by means of a simple stub value.
I much prefer Rust's approach, which is to fail out but also make it extremely easy to apply the fix the compiler has guessed.
1. The compiler doesn't usually exactly know the right thing to do. E.g. in this case presumably the error should be something like "You need to order the files so that each file doesn't depend on anything further down the list." The compiler doesn't know what that order should be (maybe in this case it could figure it out, but the point is more general than just this instance).
2. Sometimes the compiler might be able to figure out what you meant but you still did it wrong. If you accept wrong code then pretty soon people will start thinking that it is right, and then you have to support it forever. This is closely related to the thoroughly disproven "Robustness Principle", which actually leads to systems that are really not robust. HTML parsing is a good example (though mostly fixed today).
If we want to steer programming in that direction, we should teach functional programming before "traditional" programming. However, even if we manage to do that I'm not convinced that it will make a different. People think procedural and it seems that the abstraction of first order functions is hard.
For quite a long time F# simply wasn't ready, and by the time it was C# had already become an industry behemoth.
But more critically, it's not a language that's officially supported by Unity. That's enough for it not to be a wise choice to be betting a project on it where there are dozens of jobs on the line, and families that could be impacted.
I can't help but think that this concern isn't simply isolated to Unity software development; where else has the decision been made to not use F# on account of it not enjoying as much industry support as C#?
I see no point in F# other than "well, it's a nice-ish ML for .NET", and the article does nothing to help with that (file order? really? that's what you're going for as the first point to make about a language?) .
Does F# avoid that?
Yes, it's not a fundamental limitation of the language itself. But considering the amount of hypothetical efforts required to fix all that vs investments from MSFT in F#, it is fundamental. F# lags by several years behind JIT and TPL improvements, the issues are mostly known. But it feels like it's not that important for F#. It's is not for writing fast libraries, but for Python-like use cases, explorative programming, or writing code fast when performance is not important (no hot loops in F# code) but strict typing discipline makes code less buggy and more maintainable from the first attempt. They used to say that "if F# code compiles, it's probably correct" - that is close to the truth, but do not expect top performance without fighting with the F# compiler. Even one of the best known and oldest F# library FParsec has it's high-performance parts in C# - that's telling.
To be more specific, it has a C# library so it can use _unsafe {}_ blocks to perform manual memory management. This is one key performance-oriented feature that F# lacks.
Other than that, you _can_ write F# that's about as fast as non-unsafe C#, although it means giving up most of the nicer and safer features of F#. Use mutable structs and classes instead of immutable records, for/while loops instead of higher-order functions, magic values instead of option/result types, etc... I've done it in a couple of hot paths where it made sense, but quite reluctantly.
Inline functions are still fine though for writing zero-cost helpers, and I don't think C# has them (there's an <AggressiveInlining> attribute but IIRC it's just a hint, the compiler isn't required to actually obey).
Ironically, F# _could_ become the best language for high-performance .NET programming, because it supports directly inlining IL instructions intermixed with regular code (whereas C# has to go through the ILGenerator class). Unfortunately it's considered such a niche case that it's not planned to be expanded beyond the standard library, and to use it in your code you have to enable an undocumented / unsupported compiler flag.
In F#, you cannot disable inlining of small functions. It does IL source code inlining, like copy-paste, not machine code inlining. That increases generated dll/exe size a lot for generics. And sometimes you do not want to do that because it's worse for performance. There is an issue for that: https://github.com/fsharp/fslang-suggestions/issues/838
In C#, the AggressiveInlining attribute works well, in predictable manner. Non-inlineable cases are well known (`throw\switch\fixed\try..catch\calling delegates` and some more https://github.com/dotnet/runtime/blob/master/src/coreclr/ji...).
> because it supports directly inlining IL instructions intermixed with regular code
This works for very simple things only. And using InlineIL.Fody, Sigil, raw IL.Emit or just raw IL code as text is not that more difficult if you already know IL.
> you _can_ write F# that's about as fast as non-unsafe C#
I tried this several times. It always ends with fighting the compiler more than just rewriting in C#, even without the `unsafe` keyword. In most cases due to generated IL that I cannot control from F#.
Also, most simple tail calls are rewritten by a compiler to a loop, but if you look at the generated IL, there are multiple temp variables, locals, needless assignments. Maybe JIT is able to eliminate those, or maybe not... In C# I could get IL that reflects what I write, without surprises.
This also means that a lot of F# functions that are not inlined by F# source-code inlining itself effectively have NoInlining attribute. E.g. some helper method `if x then y.call() else z.call()`, if not inlined by F#, will never be inlined by JIT due to .tail prefixes before the methods calls.
So, we just carry on using VB.NET, C# and C++ instead.
Libraries spring to life as reusable parts from large scale projects.
So the ROI of context switching to F# in the middle of a project, isn't that much if the language is reduced to expressing algorithms.
Proximal? Maybe you mean appropriate? Or incremental?
- F# has function composition operators
- F# functions are curried and support automatic partial application
- F# variables and data structures are immutable by default
- F# has powerful global HM type inference
- F# uses option & result monads over exceptions and null
- F# has algebraic data types with exhaustiveness checking
These capabilities make writing code in F# a very different experience from C#. Some of these can be added to C# as features, but many things are fundamental parts of language design that are hard to change afterwards.
On top of that I find functional first languages are great for forcing you to learn functional styles that you can later user in languages like C#.
C# is a brilliant language and I wouldn't knock it. I'd use that as a first option at work but on a hobby project I'm going to play with F#.
I believe winforms and WPF has always been usable but not with the visual designer tooling in visual studio.
UWP has been trickier though to my knowledge.
Although I miss type providers, enforced lack of cycles and other nice things, like syntax:
https://contributors.scala-lang.org/t/scala-3-very-impressiv...
Why would I embrace/commit to any particular paradigms? I would use whatever I believe is best suitable for particular task. All those are just tools like a screwdriver. They're here to work for us, not the other way around.
I do not care about some generic "greater good". It does not exist. In my context "greater good" is delivering products while satisfying business and technical constraints of a given customer/s to a reasonable degree.
I think F# is an improvement to C# just like how C# was an improvement to VB.NET, which was an improvement to VB6.
However, it's not really a hill I'd die on, frankly new co-workers complaining about missing curly braces gets really old after the first day. Ultimately most programmers just don't care about using the best tools, and would still be happy using VB6 if the industry as a whole hadn't moved them along kicking and screaming into C#.
If I'm working alone, I'll choose the best tools for the job, and I tend to think F# in modern dotnet core is one of the best tools for backend servers out there. It's much more coherent then Scala, less mushy at large codebase size than Clojure, very performant, and has great libraries like aspnet core, and compiles so much faster than Haskell and has an incredible wealth of better libraries. I also prefer a more functional style than Kotlin, Go, Java, or C# provide, because for me that means fewer unit tests to get the same confidence.
There's plenty annoying with the language, but it's a great hybrid with reasonable tradeoffs.
My elevator pitch typically is: with F# I need to write fewer unit tests to get the same confidence I'd need elsewhere, and that means more time programming.
Established/large: https://rocketmortgage.com
That made me blink.
And then I found out they meant the F# software foundation, not the Free software foundation.
It seems like a very obvious misunderstanding to make, and IMO they should avoid causing it by using another abbreviation than this one which is already very well established in programming circles.
Don't be deceived by low rating. It's low because people expected a course on syntax.
Also other continuations are as below:
https://www.udemy.com/course/functional-application-designin...
https://www.udemy.com/course/end-to-end-real-world-applicati...
And if you have any questions find me from @OnurGumusDev on twitter and I will gladly help
Compositional IT has a lot of good blog posts on how they use F# to solve real world problems.
Kit Eason's Stylish F# is a good book.
The major difference I would say, is that you are required to use botnet alongside of node. (dotnet to compile to JS, then node to bundle with wepback or anything else)
Also, you can use the same language to build high performance backend with giraffe [2] (better than node). And build performant native application with fabulous [3].
There is an experimental typescript compilation. Which will be great, because it will make using F# less hostile in an environment where the winner takes all.
[1] https://fable.io
F# targets .net, javascript, and the Xamarin library targets mobile (although I haven't tried it yet).
They're all typed ml languages.
Obviously I was asking about using F# to create web applications versus using BuckleScript or Reason.
just like C#, it's dotnet after all, same engine