F# Journey: Course 3 – Discriminated Unions

By | September 3, 2015

It has been a long time since my last post here.

One of my colleagues told me that the receptiveness of the human brain shrinks after reaching the 27 year. So it’s about time to learn F# before it’s too late! 🙂

In this post I want to present an calculator example with discriminated unions. I think it’s an nice example which shows the power of the F# language.

As you can see in the code block below, I’ve defined a mathExpression descriminated union with the options “Add” and “Substract”. Both are accepting a tuple of two ints as a parameter.
The calculate pattern matching is used for the evaluation of the mathExpression.
At the bottom of the code block you see how the code can be utilized. With the current construction we don’t support nested operations.

type mathExpression =
        | Add       of int * int // tuple of two ints
        | Substract of int * int // tuple of two ints

    let calculate expression =
        match expression with
        | Add(left, right)       -> left + right // plus
        | Substract(left, right) -> left - right // minus

[<EntryPoint>]
let main argv = 
    let addition = Add(1, 1)
    let substraction = Substract(2, 1) 
    
    let addResult = calculate addition
    let subResult = calculate substraction

    printfn "addResult: %i" addResult
    printfn "subResult: %i" subResult
    0

Now let’s move one step further by enabling our calculator to evaluate nested operations. And we can do this by simply extending few pieces in our existing code. (See code block below)
I’ve added the “Constant” of type int to the mathExpression union. This represents a number within a formula.
I also changed the “Add” and “Substract” in order to accept a mathExpression and not only int values. This allows me to combine Add with Substract and vice versa.
In order to evaluate the expression we need to implement a recursive pattern matching and adjust “Add” and “Substract” cases in order to re-call the “calculate”.
With these few changes we enabled the calculator to deal with nested operations.

This is the beauty of F#. It would definitely take more effort to implement this in C#.

type mathExpression = 
        | Constant  of int                              // represents a number
        | Add       of mathExpression * mathExpression  // tuple of two mathExpressions
        | Substract of mathExpression * mathExpression  // tuple of two mathExpressions

    let rec calculate expression =
        match expression with
        | Constant(x)            -> x
        | Add(left, right)       -> calculate left + calculate right // plus
        | Substract(left, right) -> calculate left - calculate right // minus

[<EntryPoint>]
let main argv = 

    let addition = Add(Constant(1), Constant(1))
    let substraction = Substract(Constant(2), Constant(1)) 

    // NESTING!
    let complex = Add(Add(Add(Constant(1),Constant(1)), Substract(Add(Constant(1),Constant(2)),Constant(2))), Substract(Constant(4),Constant(1)))
    
    let addResult = calculate addition
    let subResult = calculate substraction
    let comResult = calculate complex

    printfn "addResult: %i" addResult
    printfn "subResult: %i" subResult
    printfn "comResult: %i" comResult

    0