dev fsharp

I finished the Pluralsight course finally. I’m still studying F# 2 pomodoros a day but lately lost he motivation to publish the notes. In this post I’ll tidy up the notes. In order to maintain my cadence I think I had better develop more stuff instead of covering theoretical subjects.

More Notes

  • Upcasting / Downcasting To upcast :> operator is used. Alternatively the keyword upcast can be used to achieve the same results. It performs a static cast and the cast is determined at runtime.

Downcasting is performed by the :?> operator or downcast keyword.

  • Abstract classes Abstract classes are decorated with **[]**. To mark members **abstract** keyword is used:
abstract Area : float with get
abstract Perimeter : float  with get
abstract Name : string with get
  • obj is shortcut for System.Object
  • do bindings perform actions when the object is constructed. do bindings are usually put after let bindings so that code in the do binding can execute with a fully initialized object.
  • unit is equivalent of void
  • tabs are not allowed as they can indicate an unknown number of space characters and as spaces and indents matter
  • ‘a means generic. By default a function f is infered as ‘a -> bool meaning it takes a general parameter and returns boolean
  • Providing an incomplete list of functions result in a new function (currying)
  • Getting values from tuples: fst gets the first value, snd gets the second value
  • You can attach elements to a list by using the :: (cons) operator
  • @ operator Concatenates two lists.
  • Exceptions can be thrown using raise function. Reraise function rethrows an exception
  • BigInt (C# and VB) don’t have support for arbitrarily long integers

Resources

dev fsharp

Going over the F# Pluralsight course I learned a few more things and thought I should use them to improve my world-famous Rock-Paper-Too-Long-To-Type game.

New tidbits and improvements in the game

  • new keyword is only required when the type implements IDisposable. So no need to use them on my RPSLS object. It works exactly the same.

  • default constructor can be defined such as

new() = Car("red", 3)
  • You can access the constructor parameters anywhere in the object so there is no need to assign it to another value.

  • Assigning values to enum values makes it compatible with other.NET languages. When I assigned values to moves an interesting thing happened. I stated getting this error: Enumerations cannot have members So you can overload operators in a discriminated union in F# and you can use it in F# only but if you want your type be compatible with other CLR languages than you can only use it as a regular enum.

After I assigned the values my Move discriminated union became:

type Move = 
    | Rock = 0
    | Spock = 1
    | Paper = 2
    | Lizard = 3
    | Scissors = 4

So no more overloaded minus operator which significantly reduced the lines of code in the type. After Googling a bit I found out that generally the above values are assigned to moves the winner is determined by extracting computer number from the player number and applying modulo operator. For example: When player plays rock (0) and computer plays paper (2)

difference = player - computer = 0 - 2 = -2
result = -2 % 5 = 3 --> Python returns 3 after this operation

if result < 3 then player wins
if result >= 3 then computer wins 

Apparently in F#, -2 % 5 = -2! So I had to add 5 before applying modulo operator:

let diff = ((int)(this.PlayerMoves.Item(i) - ComputerMoves.Item(i)) + 5) % 5

Conclusion

I’m still working with the PluralSight course. In the next post I’ll examine type casting, abstract types and do bindings etc

Resources

dev fsharp

When I first came up with a complete program here I was extremely happy. Functional programming feels like insurmountable (less so now but still) and building a fully functional program in F# felt great. Unfortunately, the moment has passed very quickly! Now it’s time to revisit and improve the Rock-Paper-Scissors-Lizard-Spock game. My main goal now is add

  • Convert the game into a class
  • Add exception handling to handle invalid user input
  • Add unit tests

What’s needed

So first I had to investigate a few concepts to accomplish these goals. PluralSight course on F# was a very helpful resource.

First version was not testable because it generated random moves inside the game and there was no way of anticipating the outcome. So I needed to harness some constructor Dependency Injection like this.

type RPSLS(userInput: string, moveGenerator: IMoveGenerator) = 
    let mutable playerScore = 0
    let mutable computerScore = 0
    let moveGen = moveGenerator

When the game is run from the console application the RPSLS object is created with a random move generator as usual so the gameplay has not been affected. But now the tests can build the object with a FakeMoveGenerator that implements the same IMoveGenerator interface.

So the actual move generator the game uses becomes a separate object like this:

type RandomMoveGenerator() = 
    member this.GenerateMove(n) = (this :> IMoveGenerator).GenerateMove(n)
    interface IMoveGenerator with
        member this.GenerateMove(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
                | _ -> failwith "Unexpected move"
            ]
            output

and the one tests use is like this:

type FakeMoveGenerator(moves : List<Move>) = 
    let mutable moveList = moves
    
    member this.MoveList 
        with get () = moveList
        and set (value) = (moveList <- value)

    member this.GenerateMove(n) = (this :> IMoveGenerator).GenerateMove(n)
    
    interface IMoveGenerator with
        member this.GenerateMove(n) = 
            let output = [ for i in 1 .. n -> 
                moveList.Item(i-1)
            ]
            output

And they both implement the same interface IMoveGenerator:

type IMoveGenerator =
    abstract member GenerateMove : int ->  List<Move>

Another benefit of this is the game can be improved easily with advanced move generators. For example a move generator can be implemented to generate specific move sequences. There is an advanced strategy guide here which is an interesting read.

Installing xUnit and xUnit Runner

Installing xUnit is pretty straightforward. Just use NuGet and add the package. For runner, apparently there was VS etension that needed to be installed separately but it’s no longer the case. Check out this guide to find out how to install xUnit test runner. It makes

Testing

I added a library to project for my tests, added xUnit and xUnit runner from NuGet I was ready to go.

So by decorating the test methoids with [] attributes I was able to run my tests to my predictable version of the game:

[<Fact>]
let Game_Ends_With_Correct_Output_3_Moves_0_to_1() =
    let fakeGen = new FakeMoveGenerator([Move.Rock; Move.Rock; Move.Paper])
    let newGame = new RPSLS("r r r", fakeGen)
    newGame.RunGame()
    Assert.Equal(0, newGame.PlayerScore)
    Assert.Equal(1, newGame.ComputerScore)

Exception Handling

As the game is created with the user input I wanted it to check the user input before it ran the game and throw an exception if the input was erroneous. Throwing an exception is carried out with failwith keyword. That’s straightforward. Handling it on the other hand came with a little surprise:

There is a try…with block which is corresponds to standard try…catch. And there is a try…finally block but they is no try…catch…finally block so they had to be used separately:

[<EntryPoint>]
let main argv = 

    try
        try
            let userInput = Console.ReadLine()
            let newGame = new RPSLS(userInput, new RandomMoveGenerator())
            newGame.RunGame()
        with
            _ -> printfn "An error occured"
    finally
        printfn "Press any key to quit"
        Console.ReadKey()

    0

In order to accomplish what I set out for I had to use two nested try blocks. Can’t say it looks great but until I get more accustomed with it I’ll just go along with quirks. At the moment it’s entirely possible that there’s a better alternative so I hope that’s the case here. Either way, it does the job after all.

Conclusion

Final version is on GitHub. I might set sail to other seas and start new small projects before I revisit this one.

Resources