Taste of F#

As a developer, it is always good to learn new things and experimenting. A little while ago I started learning OCaml (haXe's compiler is written in OCaml), but because of lack of good tooling I decided to learn F#, which is basically OCaml with .NET bindings. I still remember my friend Joa trying to convince me to learn Scala, but I don't know why, I did some C# in the past and I like Visual Studio, so I checked F#, you can run on Windows and MacOS and Linux using Mono.

So, the funny thing about F# is that most of people will tell you, what the hell is this ? Or, why are you learning this ?

The answer is, because it is fun and efficient, and there may be some good things to maybe bring to ActionScript, who knows. F# is a functional programming programming language from Microsoft Research, and is highly used in finance, simulation, parsers (compilers) and more generally large data processing in conjunction with FSLex and FSYacc available with F# PowerPack library. F# is also extremely efficient at prototyping, thanks to the F# interactive mode (REPL), no project to create, just type the lines of code directly through REPL, something we should have for Flash development.

I will not dive into the details of functional programming, I want to just show you why it is a cool language and later on, see the value of functional programming.

The basics

So let me show you a few cool things, you will see that the F# syntax is extremely concise and lightweight, so this is how you would define a value :

let a = 12

First, you notice two things, there is no var, cause as F# is a functional programming, you quickly discover that the idea is that nothing changes, so there is no such a keyword as var, we rather say that we declare a value 12 bind to the identifier a, a little bit like with mathematics, be a the value 12.

Notice, that there is no type specified, cause everything is inferred by the compiler and the tool (Visual Studio) automatically detects the type when typing code. You can define type if you want to to resolve ambiguities or when interacting with C# libraries for instance. By using REPL (F# interactive) we can compile this and get instant feedback about the result :

val a : int = 12

Pretty nice, int is inferred, now let's change the definition, and define this :

let a = 12.0

Automatically inferred as a float :

val a : float = 12.0

Easy right ? Even better, let's now define a list :

let names = [ "Bob", "Stevie", "Ricky" ]

Let's compile it, we then get :

val names : (string * string * string) list = [("Bob", "Stevie", "Ricky")]

The compiler infers automatically that all items are String grouped in a tuple in a list.

F# is not a "pure" functional programming language, cause the language is flexible enough to allow imperative concepts like mutable data (variable). By default everything is immutable, once a value is set, you cannot change it, if you really need to, you will use the mutable keyword :

let mutable a = 30

This forces you to design scalable code. It makes parallelizing of code much easier and removes race conditions and highly reduces side effects. Like, oh, yes I had this variable changed by this function, and I did not expect that. But let's have a cool at those cool little things called tuples.

Tuples and Record types

Let's define what we call a tuple in F#, basically they allow you to group values, using different types or the same, like this :

let person = ("Bob", 180, "SF")

Let's compile this, nicely inferred :

val person : string * int * string = ("Bob", 180, "SF")

Now, we can also construct a tuple using list comprehensions (covered later) :

let person = ("Bob", 180, "SF", [ for x in 1..10 -> x * x])

This allows us to construct a list out of a simple computation, this would result in :

val person : string * int * string * int list = ("Bob", 180, "SF", [1; 4; 9; 16; 25; 36; 49; 64; 81; 100])

Cool ? The power of tuples is that you can then access the values very elegantly, let's say you would like to retrieve its values, you would write :

let firstName, height, town, data = person

And you would get :

val town : string = "SF"
val height : int = 180
val firstName : string = "Bob"
val data : int list = [1; 4; 9; 16; 25; 36; 49; 64; 81; 100]

Now, you can also use it in a function, allowing you to return multiple values beautifully :

let getHelloWorld =
  let a = "Hello"
  let b = "World"
  (a, b)

Notice how we returned the tuple, we did not use a return statement. We just specified the tuple at the end of the function. Yes, in F#, the last statement in a function is automatically returned.

Let's test it :

val getHelloWorld : string * string = ("Hello", "World")

Good, now to to retrieve and assign the values, we would just list the bindings we want before calling it :

let hello, world = getHelloWorld

And we would get :

val hello : string = "Hello"
val world : string = "World"

Really nice :)

Now, you can also use the keyword fst and snd to pick the value you want at anytime :

let pair = (true, false)
let a = fst pair
let b = snd pair

And if you do not need value, just ignore it with _ :

let pair = (true, false)
let a, _ = pair
let _, b = pair

To get this result :

val pair : bool * bool = (true, false)
val a : bool = true
val b : bool = false

Now if you wanted to have fields on your tuple, you then use record types :

type Person = { firstName : string; lastName : string }

let firstPerson = { firstName = "Bob"; lastName = "Groove" }

Which is executed as :

type Person =
{firstName: string;
lastName: string;}

val firstPerson : Person = {firstName = "Bob";
lastName = "Groove";}

List comprehensions

Now let's go deeper and come back to list comprehensions, to fill a list when created, I would write :

let numbers = [ 1..10 ]

Output :

val numbers : int list = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]

But what if you want only multiple of two ? Then, you specify the step size between the dots :

let numbers = [ 0..2..20 ]

And you get :

val numbers : int list = [0; 2; 4; 6; 8; 10; 12; 14; 16; 18; 20]

You need them reversed ?

let numbers = [ 20..-2..0 ]

And you get :

val numbers : int list = [20; 18; 16; 14; 12; 10; 8; 6; 4; 2; 0]

Of course, it works also with chars :

let chars = [ 'A'..'Z' ]

And you get :

val chars : char list =  ['A'; 'B'; 'C'; 'D'; 'E'; 'F'; 'G'; 'H'; 'I'; 'J'; 'K'; 'L'; 'M'; 'N'; 'O';   'P'; 'Q'; 'R'; 'S'; 'T'; 'U'; 'V'; 'W'; 'X'; 'Y'; 'Z']

Units of measure

Another great feature is units of measure, which allows you to assign measures to your bindings, preventing you from doing calculation errors. For instance, multiply inches by cm could yield again to a bug, to limit the risks and increase safety you can write :

[<Measure>] type inches
[<Measure>] type cm

let a = 45<cm>
let b = 200<inches>

let height = a + b

This code would yield to a wrong result, if we try compiling the code above, fortunately, the compiler tells us ahead of time what is wrong :

stdin(233,18): error FS0001: The unit of measure 'cm' does not match the unit of measure 'inches'>

You can imagine the value of this when working with multiple currencies, or doing all kinds of simulation with different units of measurement.

Pipe forward operator

Another beauty is the pipe-forward operator, simplifying the way you pass values to functions and make your code much more readable and simple. Let's say you need to calculate the square of a value, round it and then gets its absolute. In many languages, you would write this, similar too :

var value:Number = Math.abs ( Math.round ( Math.sqrt ( 3.56 ) ) );

The complete opposite of how we just expressed it and how your brain would prefer reading it, in F#, you would write :

let result =
  3.56
  |> System.Math.Sqrt
  |> System.Math.Round
  |> System.Math.Abs

Much simpler to read isn't it ? When compiling it, you get as a result :

val result : float = 2.0

Another example of the pipe forward operator, in the following code, we prefill a list, then square each element. When then return a new a list that we pass to Seq.average to calculate the average value :

let numbers = [ 0.0..2.0..20.0 ]

let result =
  numbers
  |> Seq.map ( fun x -> x * x )
  |> Seq.average

And get as a result :

val result : float = 140.0

When using the pipe forward operator you then realize that you do not use loops that much anymore. But let's cover those in F#.

Loops

Loops are more an imperative style of programming, but again F# allows you to use them if needed, to create a simple for in loop :

for i in 1 .. 10 do printfn "%d" i

For a simple for loop :

for i in 1..2..10 do printfn "%d" i

We would get :

1
3
5
7
9

For a simple incremental for loop :

for i = 1 to 10 do printfn "%d" i

And to decrement, we just use downto :

for i = 10 downto 0 do printfn "%d" i

So if we were to calculate the square of each value of a list, and sum the total, here is what we would write in imperative F# style :

let numbers = [ 0..3..30 ]
let square x = x * x

let sumSquare nums =
  let mutable buffer = 0
  for i in nums do
    buffer <- buffer + square i
  buffer

let result = sumSquare numbers 

Which would output :

val result : int = 3465

Notice how you need to describe each step, a temporary buffer value, a loop, modify the value for each iteration and return the buffer. Now in a more functional way, you would write :

 let sumSquare nums =
  nums
  |> Seq.map ( fun x -> x * x )
  |> Seq.sum

And get the same result :) Let's have a look at union and sum types now.

Union and sum types

Now, here is again a concept I really love, union types. Let's say you want to define a type, and at the same type, associated types, all this in one line, well simple :

type Music = Funk of string | Soul of string | Jazz of string

Now, if we need to create those instances of styles of music :

let a = Funk "Stevie Wonder"
let b = Soul "Donnie Hatthaway"
let c = Jazz "Incognito"

Pattern matching

When using recursion, to let's say define a factorial function, we can write the following code :

let rec factorial n =  if n = 0 then 1 else n * factorial ( n - 1 )

let result = factorial 6

And we would get as a result :

val result : int = 720

But we can use what is called pattern matching, allowing a better and powerful way to handle conditions, more like a super concise switch case :

let rec factorial n =
  match n with
  | 0 -> 1
  | n -> n * factorial(n - 1)

But you could also use the shortcut function, which implies that you want to process pattern matching over its argument, so we could compact the lines above to :

let rec factorial = function
  | 0 -> 1
  | n -> n * factorial(n - 1)

Which would produce the same result but with a more concise syntax. Thanks to this lightweight and minimal syntax it is then very easy to adapt equations, let's say you want to define a fibonacci function :

Fibonacci number

You literally can port the equation directly with very minimal syntax keeping code clean and easy to read :

let rec f n =
  match n with
  | 0 -> 0
  | 1 -> 1
  | _ -> f( n - 1 ) + f( n - 2 )

Or even shorter :

let rec f n =
  match n with
  | 0 | 1 -> n
  | _ -> f( n - 1 ) + f( n - 2 )

Notice how we used the _ statement as an else.

In the following example, we use pattern matching with union types :

type Music = Funk of string | Soul of string | Jazz of string

let getTypeMusicMood n =
  match n with
  | Funk n -> "Sweet!"
  | Soul n -> "yeah soulful!"
  | Jazz n -> "Jazzzy!"
  | _ -> "unrecognized music type"

let artist = Funk "James Brown"
let result = getTypeMusicMood artist

Which would result :

val result : string = "Sweet!"

That's what I wanted to share with you for now!
I will keep digging into this language and discover new things, I am sure there are a lot of things we could bring to Flash ;)

Comments (12)

  1. Bruce LANE wrote:

    I keep switching between Flash Builder and Visual Studio, I love both, actionScript and C# are my preferred languages!

    Sunday, July 3, 2011 at 8:44 am #
  2. Danyal wrote:

    Lovely introduction, you’ve got me interested in having a go at the language, thank you.

    Sunday, July 3, 2011 at 11:51 am #
  3. Mehmet wrote:

    Python can be considered as well.

    Sunday, July 3, 2011 at 12:06 pm #
  4. fixplz wrote:

    >The compiler infers automatically that all items are a String in a list, and there are 3 of them.

    That’s a list with one tuple in it.

    | _ -> f( n – 1 ) + f( n – 2 )

    There’s no `n`.

    It’s a bit late to have this little understanding of these things.

    Sunday, July 3, 2011 at 3:29 pm #
  5. focus wrote:

    Nice language and very nice article. Thanks for an enlightenment, Thibault!

    Sunday, July 3, 2011 at 10:23 pm #
  6. Michael R. wrote:

    It could take some time to get used to it but could might turn out to be quite comfortable. I like “Pattern matching”, switch/case would definitely take more space.

    Monday, July 4, 2011 at 2:25 am #
  7. Todd Cullen wrote:

    If you like F# functional goodness, check out Erlang’s pattern matching.

    http://learnyousomeerlang.com/syntax-in-functions#pattern-matching

    Allows for some crazy method overloading and enumeration wizardry :)

    Monday, July 4, 2011 at 2:38 am #
  8. Thibault Imbert wrote:

    Hi fixplz,

    Yes, this is normal. When using the function keyword, automatically you perform pattern matching over the argument passed. So in the example, I could have named n any value, x, y, z, anything.

    Hope this makes more sense!

    Thibault

    Monday, July 4, 2011 at 6:28 am #
  9. Joa Ebert wrote:

    Hey Thibault,

    you know there is already a REPL builtin to avmshell. Just run ./avmshell -repl and you get it.

    What a pity you did not dig any deeper into Scala. F# is also nice, but yes it belongs to the ML family.

    Best

    Wednesday, July 6, 2011 at 10:14 am #
  10. Thibault Imbert wrote:

    Hey Joa,

    Yes, I heard about that when I asked internally about this. But I have been told it does not support all of AS3 and would require serious work to be considered complete :(

    But I will give it a try, it seems like it is already complete enough to start experimenting and prototyping with it.

    Both languages have a lot of similarities, learning one is not lost effort for the other :)

    Thibault

    Thursday, July 7, 2011 at 6:21 am #
  11. fixplz wrote:

    I’m saying your post has mistakes.

    val names : (string * string * string) list = [("Bob", "Stevie", "Ricky")]

    This is a list containing one tuple.

    let rec f = function
    | 0 | 1 -> n
    | _ -> f( n – 1 ) + f( n – 2 )

    You don’t introduce `n` here.

    Thursday, July 7, 2011 at 7:41 am #
  12. Thibault Imbert wrote:

    Hi fixplz,

    Good catch! Sorry for the confusion. Fixed those!

    Thibault

    Friday, July 8, 2011 at 3:31 am #

Trackbacks/Pingbacks (3)

  1. Taste of SCALA « badmood.eu on Sunday, July 3, 2011 at 6:48 pm

    [...] L’article de Thibault Imbert consacré à F#. [...]

     
  2. Async workflows in F# - ByteArray.org on Wednesday, December 21, 2011 at 12:51 pm

    [...] I thought I would share some more cool stuff regarding F#. I posted a little while ago a little preview of what is F# and how it works. I would like to go deeper here and cover a beautiful concept called asynchronous [...]

     
  3. [...] Zynga released this week an open-source project called PlayScript, allowing ActionScript 3 developers to target mobile platforms leveraging the Mono runtime. For the context, Mono is an open-source implementation of the .NET runtime, with support for C#, F# and other languages. You want to develop or reuse a library developed with these languages? Like an AI library using beautiful F#? No problem. (F# anyone?) [...]