Simple Calculator In F#
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 CodeThe 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 0Typically, 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.BottomRightAll 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].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 + 50We 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 // 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:
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 // 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() ConclusionI 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.