DEV Community

Lucis
Lucis

Posted on

Simple Things with F#

What things?

So, I'm very passionate about learning new programming languages and discovering why people like such languages. Is it a perfomance aspect? Robustness? The code looks pretty?

I tend to always go for the language website itself looking for information of "how to start" and, most of the time, I find a pretty solid documentation, with nice references to frameworks, online courses and all... But, usually, I have to read different resources for building a "simple complete" thing (like a server or so), so I decided to build a series of posts telling how to build the basics with language X?

For the basics, I chose:

  • Implementing the QuickSort algorithm
  • Reading a file from the filesystem
  • Building a HTTP server that parses JSON

Depending on the language and its environment, I may talk about installation and setup.

Let's go with F#

So, F# (pronounced F-sharp, and also how you might get better results on Google) is a programming language from Microsoft, part of the .NET framework, and it supports multiple paradigms, although it's way more used as a functional language, coming with a strong type system. F# is part of the ML family, being inspired by the language OCaml. It has a great community, multiple tools to using it in different scenarios (like turning into Javascript), and the F# code usually looks really concise, specially when building complex systems with lots of entities.

There's a great website with resources about F# that every developer should read: F# For Fun And Profit

For start using F#, you can read the guide from Microsoft, where it tells you how to install it on different platforms and integrate it on your preferred code editor. On my setup I use the dotnet CLI from the .NET SDK.

After all setup, run dotnet new console -lang F# -o simple-things. It will scaffold a simple console application. You can test it entering the simple-things generated directory and running dotnet run or dotnet watch run for re-running on every change. Opening Program.fs will show the code for the application.

1. QuickSort

For the sorting code, I chose this from StackOverFlow. It uses a bunch of nice features from the language. You can paste it right over the main func:

let rec qsort: int list -> int list = function
    | [] -> []
    | x::xs -> let smaller = [for a in xs do if a<=x then yield a]
               let larger =  [for b in xs do if b>x then yield b]
               qsort smaller @ [x] @ qsort larger
Enter fullscreen mode Exit fullscreen mode

The let form declares the function qsort that supports recursion, which is not the default, indicated by the keyword rec. The int list -> int list is the type annotation: this function receives a list of int and returns one also.

The | stuff going on there is called pattern matching, and it's a very useful tool with much more uses. This kind of function declaration omits its parameter declaration, and will try to match it right away. If it's a empty collection, it returns []. If not, it will perform the pivoting of the algorithm.

The for .. in .. form it's a handy tool for dealing with collections, and you can read more about it here. One could also use List.filter or List.partition for creating the new lists.

And, finally, the @ operator is used for concatenating lists.

Calling a function in F# is as simples as writing the name of the function, a space, and the input. No parenthesis necessary. You can test it!

2. Reading a file from the filesystem

This is the part where we use F#'s .NET API, what's really cool. There's also a inter-op with C# code, so that makes finding packages really easy. For reading a file we'll use the System.IO.File.ReadAllText function, which takes a file path and returns its text content. Just add open System.IO to the beginning of the file and let's try:

    let readFile(path: string) = File.ReadAllText path
Enter fullscreen mode Exit fullscreen mode

And that's just it. You can test it calling readFile "1.txt" for example. I explicitly added the parameter path here for showing how we can do it.

3. Building a HTTP server that parses JSON

This is, with certainty, one of the most popular topics regarding any programming language. Using F#, you can setup a HTTP server without a hassle, and there are a lot of other options if you wanna do things differently.

When doing functional programming, the simplest approaches are usually favored. Instead of using a complex framework with all the boilerplate needed, you can get some libraries, hook them together, and get the same end result. Of course, this comes with the cost of more decision making, what can be harder for beginners, but the community are usually quite helping about starter guides. For this post, I've chosen to use Suave.

Parsing

JSON is a popular format for sending and receiving data over the WEB, used by a number of WEB APIs. It's simple, human-readable, and lighter than other formats. Since it's not a core feature of F#, we will need to import a library from somewhere. There a lot of great JSON parsers out there on the .NET environment, like Newtonsoft or Chiron, but Suave already comes with one.

There are two ways you can do this: providing the input type, or reading the JSON from whatever format it came. We are using the former and you should too, since a lot of F# benefits comes from well defined types. There's a lot more about typing like the awesome type inference the language has, or the Type Providers, but it's another post's matter.

[<DataContract>]
type Input =
   { 
      [<field: DataMember(Name = "list")>]
      list: int seq;
   }

[<DataContract>]
type Output =
   { 
      [<field: DataMember(Name = "result")>]
      result: int seq;
   }

Enter fullscreen mode Exit fullscreen mode

This sets up our input and output data types, and we will use them when creating our server. We need to explicitly set the JSON keys for the keys of our types.

Creating the HTTP server

Suave is a a lightweight, non-blocking web server for F#, and it's super simple to setup a server. After installing it with dotnet add package Suave (or using NuGet directly), you can just insert on your Program.fs:

open Suave

startWebServer defaultConfig (Successful.OK "Hello World!")
Enter fullscreen mode Exit fullscreen mode

Wait for the watcher to restart your program, and you have a http://localhost:8080 on the air. With a bit more of configuration, you can setup a routing supporting other path or methods.

So, let's configure a POST route that uses our QuickSort and reads/returns JSON data.

// You need to open some packages to use this functions, check the final code below

let sortHandler: Input -> Output =
    fun input -> { result= qsort (Seq.toList input.list) }

let app = 
  choose
    [ POST >=> choose
        [path "/" >=> Json.mapJson sortHandler]]

[<EntryPoint>]
let main argv =
    startWebServer defaultConfig app
    0
Enter fullscreen mode Exit fullscreen mode

This is it. Let's test:

Testing our server on Postman

Final Code: https://github.com/luciannojunior/simple-things-fsharp

Some things to point out:

  1. The Json.mapJson comes from Suave and it basically transforms a "normal" F# function into a HTTP handler that transforms the request body into F# data (the function parameter), and also the function response into JSON ready to the response. You can learn more about it here

  2. I've run into problems using F#'s list for the JSON types, so I had to use seq (that is more advisable when integrating with .NET code), so I need Seq.toList to pass the data into our sort int list -> int list function. It wasn't necessary to transform the output due to automatic casting.

  3. It was very easy to setup this simple demo, but I took some time until realizing that a very strange error was happening because I was testing the POST route without passing a body. It wouldn't be hard to wrap mapToJson into a request-safe middleware.

  4. I use vim as an editor, and couldn't setup my ALE to work with F#, so autocompletion was not happening. I believe that using a MS editor would be a more pleasant experience.

  5. I've used dotnet because it was already installed on my machine, but for the next posts I'll probably use something like Docker.

I would appreciate some feedback, as I hope to return with the series with another language soon. See ya!

Top comments (1)

Collapse
 
64j0 profile image
Vinícius Gajo

Nice post. I'm looking for more F# content. Your post helped me to understand some concepts.