F# for the Office?

jkone27
5 min readSep 20, 2023

For enterprise, the web, data, and even more

the Office series cast, sitting on files
  • 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 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.
from sharp interactive docs, an example of a minimal .fsx file
support in VisualStudio
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 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.
Fable compiler logo, supporting Ukraine
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()

Awesome YouTube channels to learn more about F#

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! :)

--

--