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:
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:
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.
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
.
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:
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].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:
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:
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:
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
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:
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:
member this.DoOperation() =
if operation = 1 then
lblDisplay.Text <- (operand1 + operand2).ToString()
else if operation = 2 then
lblDisplay.Text <- (operand1 - operand2).ToString()
else if operation = 3 then
lblDisplay.Text <- (operand1 * operand2).ToString()
else if operation = 4 then
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.