Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / F#

Simple Calculator In F#

4.33/5 (4 votes)
13 Oct 2015CPOL4 min read 20.2K   400  
A simple calculator written in F# language

Introduction

This tip is a simple calculator program written in F# programming language. The calculator performs simple operations like +, -, * and /.

From this calculator, you can learn various features of F# language used in this calculator program such as match expression, array, accessing array element via (.) and ([ and ]) operator, object type casting, etc. And also, you will be able to know about the use of System.Windows.Forms control classes to create graphical user interface in F# language.

Using the Code

The calculator program has a main window, ten buttons for 0 to 9 number, 4 buttons for doing +, -, *, / operations and two buttons for doing equal and clear operations. The calculator also has a label control as the calculator display.

Here is the main window class of our calculator:

F#
type MainWindow() = 
    inherit Form()

In F# language, class definitions start with the type keyword.

The above class represents the main window of our calculator and it inherits the System.Windows.Forms.Form class.

Here are all the private fields of the MainWindow class:

F#
let btnNumbers :Button array = Array.zeroCreate 10

let btnAdd = new Button()
let btnMin = new Button()
let btnMul = new Button()
let btnDiv = new Button()

let btnEqual = new Button()
let btnClear = new Button()

let lblDisplay = new Label()

let mutable doClear = false

let mutable operation = 0
let mutable operand1 :Int64 = int64 0
let mutable operand2 :Int64 = int64 0

Typically, let binding is used for defining private fields and functions in F# language.

In the above codes, we make all the 0 to 9 numbers buttons as an array of Button class to make things easy. We have made the last four variables mutable because we need to modify those variable at run-time.

The following function is the initializer function of the MainWindow class. This function initializes some basic properties of the window, initializes all the buttons and the display label control. The entry point function of the program will call this function.

F#
member this.Init =
        this.Text <- "Simple Calculator In F#"
        this.Size <- new System.Drawing.Size(270, 400)
        this.FormBorderStyle <- FormBorderStyle.Fixed3D
        this.MaximizeBox <- false
        this.BackColor <- System.Drawing.Color.FromArgb(255, 225, 235)

Then, we initialize the display control which is a label control class of System.Windows.Forms namespace.

F#
lblDisplay.Location <- Point(30, 90)
lblDisplay.Size <- Size(190, 40)
lblDisplay.Text <- "0"
lblDisplay.BackColor <- System.Drawing.Color.White
lblDisplay.Font <- new Font("Arial", 16.0f)
lblDisplay.BorderStyle <- BorderStyle.Fixed3D
lblDisplay.TextAlign <- ContentAlignment.BottomRight

All the 0 to 9 buttons are initialized through a for .. in loop:

F#
for i in 0 .. btnNumbers.Length - 1 do

            btnNumbers.[i] <- new Button()

            btnNumbers.[i].Location <- Point(btnX, btnY)
            btnNumbers.[i].Size <- Size(40, 40)
            btnNumbers.[i].Text <- i.ToString()
            //btnNumbers.[i].BackColor <- System.Drawing.Color.White
            btnNumbers.[i].Click.AddHandler(new System.EventHandler(fun s e -> this.Event_Number_Pressed(s, e)))

            this.Controls.Add(btnNumbers.[i])

            if i = 0 then
                btnY <- btnY - 50
            else
                if i % 3 = 0 then
                    btnX <- 30
                    btnY <- btnY - 50
                else
                    btnX <- btnX + 50

We can see that [ and ] operator is used to access array element. In F# language, you can access array elements through using a dot operator (.) and brackets ([ and ]).

Then we initialize addition, minus, multiply, division, equal and clear operations buttons:

F#
btnAdd.Location <- Point(180, 300)
btnAdd.Size <- Size(40, 40)
btnAdd.Text <- "+"
btnAdd.BackColor <- System.Drawing.Color.FromArgb(187, 208, 185)
btnAdd.Click.AddHandler(new System.EventHandler(fun s e ->this.Event_Operation_Pressed(s, e)))

btnMin.Location <- Point(180, 250)
btnMin.Size <- Size(40, 40)
btnMin.Text <- "-"
btnMin.BackColor <- btnAdd.BackColor
btnMin.Click.AddHandler(new System.EventHandler(fun s e -> this.Event_Operation_Pressed(s, e)))

. . . . . . . . .  . . . . . . .
. . . . . . . . .

And finally, at the end of the init function, we add all the controls to our main window in this way:

F#
this.Controls.Add(lblDisplay)

this.Controls.Add(btnClear)
this.Controls.Add(btnEqual)
this.Controls.Add(btnAdd)
this.Controls.Add(btnMin)
this.Controls.Add(btnMul)
this.Controls.Add(btnDiv)

Now, we will see codes of button click event handler. In this calculator program, we have four kinds of buttons. Equal, clear, mathematical operators and 0 to 9 numbers buttons. So we have made four event handlers for those buttons.

This member function represents click event codes for the operator buttons:

F#
member this.Event_Operation_Pressed(sender : System.Object, e : System.EventArgs) = 

        let btn = this.downcastButton(sender)

        operation <- 
            match btn.Text.[0] with 
            | '+' -> 1
            | '-' -> 2
            | '*' -> 3
            | '/' -> 4
            | _ -> 1   // Default is add operation. But I don't think this will ever happen.  

        doClear <- true

        if operand2 <> int64 0 then
            this.DoOperation()
            operand1 <- Int64.Parse(lblDisplay.Text)

In the above codes, first, we convert the sender parameter from System.Object type to System.Windows.Forms.Button class type. We use a user-defined member function called downcastButton for that purpose.

To determine what kind of operation we should do now, we use an interesting feature of F# language called match expression to make things more clear. The value of operation variable will depend on the first element of sender button text array.

According to MSDN, the syntax of match expression is as follows:

// Match expression.
match test-expression with
| pattern1 [ when condition ] -> result-expression1
| pattern2 [ when condition ] -> result-expression2
| ...

To me, match expression is something like the switch statement of C like language. But of course, match expression is much more easier to use.

When any number button is pressed, if the operation variable is zero, then we add the number to the display label text and we store the number into the operand1 variable.

If the operation variable was not zero, then we also add the number to the display label text and we store the number into the operand2 variable.

Here is the number buttons click event handler:

F#
member this.Event_Number_Pressed(sender : System.Object, e : System.EventArgs) = 
        let btn = this.downcastButton(sender)

        if lblDisplay.Text = "0" then
            doClear <- true

        if doClear = true then
            lblDisplay.Text <- ""
            doClear <- false

        if lblDisplay.Text.Length < 17 then
            if operation = 0 then
                lblDisplay.Text <- lblDisplay.Text + btn.Text
                operand1 <- Int64.Parse(lblDisplay.Text)
            else
                lblDisplay.Text <- lblDisplay.Text + btn.Text
                operand2 <- Int64.Parse(lblDisplay.Text)

When the equal button is pressed, we call a function called DoOperation to calculate the operand1 and operand2 variable value and we show the result into the display label.

The calculation depends on the operation variable value that whether it should be a +, -, *, or / calculation.

Here is the DoOperation function definition:

F#
member this.DoOperation() = 
        if operation = 1 then // Add
            lblDisplay.Text <- (operand1 + operand2).ToString()
        else if operation = 2 then // Min
            lblDisplay.Text <- (operand1 - operand2).ToString()
        else if operation = 3 then // Mul
            lblDisplay.Text <- (operand1 * operand2).ToString()
        else if operation = 4 then // Div
            lblDisplay.Text <- (operand1 / operand2).ToString()

Conclusion

I think making a simple calculator will be a good practice for beginners. Although the calculator has included very simple features, I hope this calculator will help you to improve your skill in F# programming language.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)