Enter F#

fsharp, development comments edit

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.

Lecture Notes

  • 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.

Resources

Comments