EASY and intuitive: a bit like Python uses indentation for scoping, and has only 2 very simple keywords at its base: let for bindings of expressions and functions, and type for defining custom types. the last value in scope is the returned value, () is unit/void.
let myFunc a b = a + b + 1 // last value is return value // type is: int -> int -> int
type Person = { Name : string ; Age: int }
type SimpleDu = | One | Two | Three
let someList = [ 1; 2; 3 ]
let someTuple = ("hello", "tuple", 1, 2, 3, 100.0d)
let someListComprehension = [ for x in someList do x + 1 ]
//...
MAGIC TYPE INFERENCE! Not far syntactically from javascript either as it usually has no explicit typing by default, so kind of looks dynamic, but infers types like typescript, just in a smarter silent way, a bit like Flow or Reason, Elm or OCaml. Strongly statically typed with automatic type inference and generalized by default <T>!
// simple enum like union type Product = | Car | Hotel | Trip
// a real enum type SomeEnum = | First = 0 | Second = 1
// discriminated union type Order = | StandardOrder of products: Product list | SpecialOffer of products: Product list * discount: string | FreeOrder of products : Product list | EmptyOrder | TestOrder of products : Product list
// single case union type PhoneNumber = | Phone of string
// record type Person = { Name: string ; Surname: string ; Age: int; Phone: PhoneNumber }
Computation expressions for all sorts of things, async, task, query, seq, and writing succinct DSLlanguages if required
let someHotAsyncComputation () = task { let! awaitedValue = someOtherAsyncTask()
return awaitedValue.Property }
let someColdAsyncComputation () = async { ... }
let someQueryOnDb () = query { .... }
let someCustomBuilderComputation = myObjectBuilder { .... } // can create your own!
Type providers for awesome DATA strong typing on the fly within the compiler itself, kind of like rust macros, but easier. The best example is FSharp.Data, but there are many and you can also create your own. You have many for SQL as well as many other data source types, file systems (has to be ported to dotnet core..), or cloud provider storage like the S3 bucket provider, possibilities are kind of endless.
type SomeJsonProvider = JsonProvider<"myJsonFile.json">
let sample = SomeJsonProvider.GetSample() // loads based on "sample/schema"
type MyJsonFile = SomeJsonProvider.Root // i have all the type created for me!
let tests = sample.Property = 10.0m // inferred as money, strongly typed!
// now we change the property name in the file as "someProperty2" // the code will stop compiling, and it will show in intellisense
let tests = sample.Property2 = 10.0m// now it compiles
// we change the returned value in the json to string like "hello" , // it will not compile anymore untill we change
INTERACTIVE, work with both compiled or scripted versions of the language via dotnet fsi and .fsx files plus vscode + Ionide extension or vs/rider. A bit like Python REPL! awesome for prototyping and testing things line by line and seeing the results in the console, or trying out .NET libs you didn’t know about quickly.
Press enter or click to view image in full size
from sharp interactive docs, an example of a minimal .fsx file
cross-platform support for identical experience in Ionide + VsCode
REUSE all or almost all .NET knowledge if someone dev is coming from the C# language, and all the libraries you loved and used, 99% of the time will work perfectly fine with F# or will need minor adjustments.
src. any .NET lib works in F#, and a compiled F# project can be used as assembly/package or direct project reference, and vice-versa for any .NET language
COMPILE to other languages and runtimesthanks to Fable, like JS, TS, Rust, Python, and others! Not many languages have such extensibility, even have integration to work/compile to React.js via Feliz and Fable React, making it suitable for true full stack or across languages as a polyglot meta-language.
Press enter or click to view image in full size
Fable compiler logo, supporting Ukraine
TEST: it’s perfect for unit tests in Xunit, and has lots of testing library additions for TDD and BDD, and Selenium testing with Canopy.
open canopy.runner.classic open canopy.configuration open canopy.classic
//this is how you define a test "taking canopy for a spin" &&& fun _ -> //this is an F# function body, it's whitespace enforced
//go to url url "http://lefthandedgoat.github.io/canopy/testpages/"
//assert that the element with an id of 'welcome' has //the text 'Welcome' "#welcome" == "Welcome"
//assert that the element with an id of 'firstName' has the value 'John' "#firstName" == "John"
//change the value of element with //an id of 'firstName' to 'Something Else' "#firstName" << "Something Else"
//verify another element's value, click a button, //verify the element is updated "#button_clicked" == "button not clicked" click "#button" "#button_clicked" == "button clicked"
//run all tests run()
printfn "press [enter] to exit" System.Console.ReadLine() |> ignore
And there are probably more reasons, if you want to add one to the list feel free in the comments below, but hey, give it a spin, don’t give up and have fun! :)