Adventures in F# - Part 5

fsharp, development comments edit

It’s about time for me to develop some application to put the basics in use. I will develop it in Visual Studio so first is to get accustomed to using F# in VS 2013. There are 5 project types for F#:

  • Console Application
  • Library
  • Tutorial
  • Portable Library
  • Portable Library (Legacy)

Portable Library should be helpful when developing universal Windows Store apps. For my purposes Console Application and Library should be enough. Before going any further I decided to check out the Tutorial project. So below are today’s notes on using F# in VS 2013 and from the tutorial project

Notes

  • Tutorial project comes with a single Tutorial.fsx file with all the sample code. Console Application, on the other hand, comes with Program.fs. Apparently an fsx is the extension for F# script files: “An F# script file is a normal F# source code file, except that .fsx files have a few extra capabilities.”.

fsx Windows Explorer integration

  • Ctrl + Alt + F combination opens the F# Interactive Window
  • You can select a code block and run it in the interactive window by right-clikcing and selecting “Execute in Interactive” or using Alt + Enter shortcut.
  • A module is a logical grouping of related code segments. The code in a module must be indented. When types and functions are inside modules they can be accessed by their fully-qualified names from outside the module:
module MyModule1 =
    let module1Value = 100
    let module1Function x =
        x + 10

module MyModule2 =
    let module2Value = 121
    let module2Function x =
        x * (MyModule1.module1Function module2Value)

MyModule2.module2Function 5
  • Modules can have public, private or internal access modifiers. The default is public.
  • A foreach loop can be defined as for i in {values} -> … For example
let sampleTableOfSquares = [ for i in 0 .. 99 -> (i, i*i) ]
  • When defining functions parenthesis can be used optionally. I think this makes the function look more “mathy” and a littler easier to read.
let func1a (x) = x*x + 3             
  • To improve the readability further it sounds like a good idea to annotate the type always (even when it can be inferred automatically)
let func2 (x:int) = 2*x*x - x/5 + 3   
  • Boolean operations are straightforward
let boolean1 = true
let boolean2 = false
let boolean3 = not boolean1 && (boolean2 || false)
printfn "The expression 'not boolean1 && (boolean2 || false)' is %A" boolean3
  • Double-quotes can be used inside strings be enclosing them with triple quotes
let string4 = """He said "hello world" after you did"""
  • A fragment of a string can be accessed by this notation:
let string1 = "Hello"
let string2  = "world"
let helloWorld = string1 + " " + string2
let substring = helloWorld.[0..6]
  • A tuples is a set of ordered values
let tuple1 = (1, "fred", 3.1415)
  • Lists can be defined in various syntax
let list1 = [ ]
let list2 = [ 1; 2; 3 ]
let list3 = 42 :: list2
let numberList = [ 1 .. 1000 ]
let squares = 
    numberList 
    |> List.map (fun x -> x*x) 
  • Classes can be defined by type keyword
type Vector2D(dx : float, dy : float) = 
    let length = sqrt (dx*dx + dy*dy)
    member this.DX = dx  
    member this.DY = dy
    member this.Length = length
    member this.Scale(k) = Vector2D(k * this.DX, k * this.DY)
  • Generics classes are supported
type StateTracker<'T>(initialElement: 'T) = 
    let mutable states = [ initialElement ]
  • Classes can implement interfaces
type ReadFile() =
    let file = new System.IO.StreamReader("readme.txt")
    member this.ReadLine() = file.ReadLine()
    interface System.IDisposable with    
        member this.Dispose() = file.Close()
  • Arrays use a similar syntax to lists except [ ] operators are used
let array1 = [| 1 .. 1000 |]
let evenNumbers = Array.init 1001 (fun n -> n * 2) 
  • Sequences are evaluated on-demand and are re-evaluated each time they are iterated. They are defined by curly braces
let numbersSeq = seq { 1 .. 1000 }
  • Recursive functions are defined by let rec keyword
let rec factorial n = 
    if n = 0 then 1 else n * factorial (n-1)
  • Record types can be created by type keyword and curly braces
type ContactCard = 
    { Name     : string;
      Phone    : string;
      Verified : bool }
  • Union types can be created by type keyword and pipe-separated values
type Suit = 
    | Hearts 
    | Clubs 
    | Diamonds 
    | Spades
  • Option values are any kind of value tagged with either ‘Some’ or ‘None’.
  • Code can be annotated with units of measure when using F# arithmetic over numeric types
    open Microsoft.FSharp.Data.UnitSystems.SI.UnitNames

    [<Measure>]
    type mile =
        /// Conversion factor mile to meter: meter is defined in SI.UnitNames
        static member asMeter = 1600.<meter/mile>
  • Large arrays can be processed in parallel
    let oneBigArray = [| 0 .. 100000 |]
    
    // do some CPU intensive computation 
    let rec computeSomeFunction x = 
        if x <= 2 then 1 
        else computeSomeFunction (x - 1) + computeSomeFunction (x - 2)
       
    // Do a parallel map over a large input array
    let computeResults() = oneBigArray |> Array.Parallel.map (fun x -> computeSomeFunction (x % 20))

    printfn "Parallel computation results: %A" (computeResults())
  • Events are also supported
    open System

    // create instance of Event object that consists of subscription point (event.Publish) and event trigger (event.Trigger)
    let simpleEvent = new Event<int>() 

    // add handler
    simpleEvent.Publish.Add(
        fun x -> printfn "this is handler was added with Publish.Add: %d" x)

    // trigger event
    simpleEvent.Trigger(5)

Conclusion

I like the tutorial script that came with VS. It shows all basic aspects in one place. I think I’ve spent enough time covering the basics. I need to dive deeper and develop something on my own or at least check out complete applications which I’m going to do next.

Resources

Comments