For enterprise, the web, data, and even more
- 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, andtype
for defining custom types. the last value in scope is the returned value,()
isunit
/void.
let v = 3 // inferred as int
let someVoidFunc () = // accepts void/unit
() // returns void/unit
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>
! - ADT for domain modelling and DDD with DISCRIMINATED UNION types and Record types.
// 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 DSL languages 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.
// assuming our json looks like { "someProperty" : 10.0m }
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.
- GREAT IDE support in the most loved IDEs: VsCode, Rider, VisualStudio.
- 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.
- COMPILE to other languages and runtimes thanks 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.
- 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
canopy.configuration.chromeDir <- System.AppContext.BaseDirectory
//start an instance of chrome
start chrome
//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
quit()
- GREAT COMMUNITY with an awesome slack channel and plenty of learning resources: https://fsharp.org/learn/, https://dotnet.microsoft.com/en-us/languages/fsharp, https://learn.microsoft.com/en-us/training/paths/fsharp-first-steps/,
https://fsharpforfunandprofit.com/ and many more, resources are almost endless.
Awesome YouTube channels to learn more about F#
- https://www.youtube.com/@FastFSharp
- https://www.youtube.com/@amplifyingfsharp
- https://www.youtube.com/watch?v=yGzu0iDuMNQ&list=PLdo4fOcmZ0oUFghYOp89baYFBTGxUkC7Z&ab_channel=dotnet
- https://www.youtube.com/watch?v=nSOE-wVkLaE&list=PL3PIRsM7569N6XZkL1sL6-dzo5v2zPFUN&ab_channel=NiklasOPF
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! :)