I’m not a big fan of New Year’s resolutions. I was meaning to start learning F# and since it’s the new year’s 2nd day it might a good time to finally give it a shot!
Where to start
It’s always hard to find the best resource when you are starting. Some time ago I heard about a Microsoft Research project called TryFSharp.org. It’s a tutorial website geared towards the absolute beginners. It comes with a REPL editor so no extra tools are needed to start.
From now on I’m planning to spend 2 pomodoros (around 1 hour) every day to learn F#. After my first 2 pomodoros I completed the first 3 sections and below are my notes for today’s training.
- let keyword to bind names to values. These bindings are immutable. If you try to assign a value to a same name twice you get the following error:
let duplicated = "original value" let duplicated = "new value"
causes the following error:
stdin(8,5): error FS0037: Duplicate definition of value 'duplicated'
- Mutable variables can be created by explicitly specifiying mutable keyword but it should be used cautiously.
- F# is a statically typed language like C#
- printfn can be used to display messages. Strings can be formatted by using special characters such %d for int, %s for string such as
printfn "The answer is %d" 42
- let can also be used bind a name to a function. The following code
let square x = x * x square 4
produces this result in the output window:
> let square x = x * x square 4 val square : x:int -> int val it : int = 16 >
- F# is whitespace-sensitive. In the function above the body of the function was denoted by indenting it 4 spaces and return values is the last line of the function.
- In times when F# cannot determine the type on itw own, it can specified explicitly bu using type annotations. For example:
let toLeetSpeak (phrase:string) = phrase.Replace('t', '7').Replace('o', '0') toLeetSpeak "root"
In the example above it needs to be specified that phrase if of type string before String.Replace method can be called.
- Functions can be defined inside other functions:
let quadruple x = let double x = x * 2 double(double(x))
- A function can be used as an argument to another function to create what’s called a higher order function.
- Inline functions can be created such as
let square = (fun x -> x * x)
Theres are called lambda functions or lambdas.
- Lists can be created by semi-colon separated single values or a range values with .. in between such as
let evens = [2; 4; 6; 8] let firstHundred = [0..100]
- Higher-order functions can be combined with other functions such as
let firstHundred = [0..100] List.map (fun x -> x * 2) (List.filter (fun x -> x % 2 = 0) firstHundred)
which produces the following output
val it : int list = [0; 4; 8; 12; 16; 20; 24; 28; 32; 36; 40; 44; 48; 52; 56; 60; 64; 68; 72; 76; 80; 84; 88; 92; 96; 100; 104; 108; 112; 116; 120; 124; 128; 132; 136; 140; 144; 148; 152; 156; 160; 164; 168; 172; 176; 180; 184; 188; 192; 196; 200]
It first filters the odd numbers out of firstHundred list and send the result to map function to double all the values.
- Forward-pipe operator can be used to make the code easier to read when functions are chained:
[0..100] |> List.filter (fun x -> x % 2 = 0) |> List.map (fun x -> x * 2) |> List.sum
- Array indexing is zero-based.