dev fsharp

I can learn by doing so after I’ve started learning F# I had to develop some application to practice. The one I came up with is a simple game: Rock Paper Scissors Lizard Spock. First version only gets a bunch of moves from the player, generates random moves for the computer and displays the outcome as shown below:

Rock Paper Scissors Lizard Spock sample output

Implementation

First, it gets a list of moves from the user. It should be a space-separated list of moves: R (Rock), P (Paper), S (Scissors), L (Lizard) and M (M for Mr. Spock as S was taken!)

Then it converts the characters to corresponding moves and generates equal number of moves for the computer.

Next it compares both lists of moves. It uses overloaded “-“ operator of the discriminated union. If the difference is 1 it means first player won, if it’s 2 then the second move won. 0 means draw.

Finally it displays the output of each round the score after that.

Source code

Program has two files only and basic game implementation is as follows:

module Game

type Move = 
    | Rock
    | Paper
    | Scissors
    | Lizard
    | Spock

    static member (-) (x, y) =
        match x, y with
        | Move.Scissors, Move.Paper -> 1
        | Move.Scissors, Move.Lizard -> 1
        | Move.Scissors, Move.Rock -> 2
        | Move.Scissors, Move.Spock -> 2
        | Move.Lizard, Move.Paper -> 1
        | Move.Lizard, Move.Rock -> 2
        | Move.Lizard, Move.Scissors -> 2
        | Move.Lizard, Move.Spock -> 1
        | Move.Paper, Move.Lizard -> 1
        | Move.Paper, Move.Rock -> 2
        | Move.Paper, Move.Scissors -> 2
        | Move.Paper, Move.Spock -> 1
        | Move.Spock, Move.Paper -> 2
        | Move.Spock, Move.Rock -> 1
        | Move.Spock, Move.Scissors -> 1
        | Move.Spock, Move.Lizard -> 2
        | Move.Rock, Move.Paper -> 2
        | Move.Rock, Move.Spock -> 2
        | Move.Rock, Move.Scissors -> 1
        | Move.Rock, Move.Lizard -> 1
        | (x, y) when (x = y) -> 0

let GetRandomMove n = 
    let rnd = System.Random();
    let output = [ for i in 1 .. n -> 
        let index = rnd.Next(0, 5)
        match index with
        | 0 -> Move.Rock
        | 1 -> Move.Paper
        | 2 -> Move.Scissors
        | 3 -> Move.Lizard
        | 4 -> Move.Spock
    ]
    output

let GetRoundOutputText moves =
    match moves with
    | (Move.Scissors, Move.Paper) | (Move.Paper, Move.Scissors) -> "Scissors cuts Paper"
    | (Move.Paper, Move.Rock) | (Move.Rock, Move.Paper) -> "Paper covers Rock"
    | (Move.Rock, Move.Lizard) | (Move.Lizard, Move.Rock) -> "Rock crushes Lizard"
    | (Move.Lizard, Move.Spock) | (Move.Spock, Move.Lizard) -> "Lizard poisons Spock"
    | (Move.Spock, Move.Scissors) | (Move.Scissors, Move.Spock) -> "Spock smashes Scissors"
    | (Move.Scissors, Move.Lizard) | (Move.Lizard, Move.Scissors) -> "Scissors decapitates Lizard"
    | (Move.Lizard, Move.Paper) | (Move.Paper, Move.Lizard) -> "Lizard eats Paper"
    | (Move.Paper, Move.Spock) | (Move.Spock, Move.Paper) -> "Paper disproves Spock"
    | (Move.Spock, Move.Rock) | (Move.Rock, Move.Spock) -> "Spock vaporizes Rock"
    | (Move.Rock, Move.Scissors) | (Move.Scissors, Move.Rock) -> "Rock crushes scissors"
    | (x, y) when (x = y) -> "Draw"
    | (_, _) -> "Unknown move pair"
    
let GetMovesFromInput (input : string) =
    let inputList = Array.toList (input.Trim().Split [|' '|])
    let moves = List.map (fun (x: string) -> 
        match x.ToUpper() with
        | "R" -> Move.Rock
        | "P" -> Move.Paper
        | "S" -> Move.Scissors
        | "L" -> Move.Lizard
        | "M" -> Move.Spock ) inputList
    moves

And the entry point of the program that gets user input and displays the results is :

open Game
open System

[<EntryPoint>]
let main argv = 

    let mutable playerScore = 0
    let mutable computerScore = 0

    let playerMoves = GetMovesFromInput (Console.ReadLine())
    let n = playerMoves.Length
    printfn "You played: "
    for i in 0 .. n - 1 do
        printfn "%A" (playerMoves.Item(i))

    printfn ""
    printfn "Generating computer moves"
    let computerMoves = GetRandomMove n
    printfn "Computer played: "
    for i in 0 .. n - 1 do
        printfn "%A" (computerMoves.Item(i))

    printfn ""
    printfn "Results:"    

    for i in 0 .. n - 1 do
        printfn  "%s" (GetRoundOutputText (playerMoves.Item(i), computerMoves.Item(i)))
        let diff = (int)(playerMoves.Item(i) - computerMoves.Item(i))
        if diff = 1 then playerScore <- playerScore + 1
        elif diff = 2 then computerScore <- computerScore + 1
        printfn "Player: %d \t Computer: %d" playerScore computerScore

    let s = Console.ReadLine()
    printfn "%s" s
    
    0 

Conclusion

This is just the initial version (v0.1). I will keep improving it but for the time being I’m satisfied that I have a fully-working program developed in F# that uses the basics like discriminated unions, operator overloading and pattern matching. More to come soon…

Resources

dev fsharp

In today’s F# session I’ll examine a sample program. It helps to be inspired and learn more about real-life usage and capabilities of the language.

It’s definitely a fun game if nothing else and offers a lot to learn for F# noobs like myself!

Make Santa Jump

One thing to pay attention is when you first clone and build it gives compile errors.

Build error

To fix this you have reload the solution and restart Visual Studio.

Notes

  • use keyword has the same functionality as a let binding but adds a call to Dispose method. It’s like the using statement
  • open keyword is similar to using in C# but it can be used for other modules as well as namespaces
  • I added a source file called Game.fs and started getting the following error:

Files in libraries or multiple-file applications must begin with a namespace or module declaration, e.g. ‘namespace SomeNamespace.SubNamespace’ or ‘module SomeNamespace.SomeModule’. Only the last source file of an application may omit such a declaration.

Even though G came before P, Visual Studio didn’t automatically reorder files alphabetically like it would normally do with C#. Apparently even the order of files are important in F# (who knew?). There are even Move Up/Down options in the context menu. So I right-clicked Program.fs and moved it down so it would be the last source file in the project and it fixed the build error!

  • Properties can be defined with get and set members as below:
module Game

type Suit = 
    | Hearts 
    | Clubs 
    | Diamonds 
    | Spades

type Card(suit : Suit, value : int) = 
    let mutable faceValue = value

    member this.Value
        with get() = faceValue
        and set(value) = faceValue <- value

Resources

dev fsharp

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