Easy Way To Become An F# Programmer For C# Developers

The basis for Object-Oriented Programming languages started in the early 1960s, and for over 30 years, it has dominated the market. Over time, many problems in the Object-Oriented Programming paradigm have been found. This article is not to describe the OOP problems, but I have quoted a text from Dijkstra. This Dijkstra quote should be the key for you to understand the OOP problems.
 
Easy Way To Become An F# Programmer For C# Developers 
 
Functional Programming (FP) is another programming paradigm, and it exists even before Object-Oriented Programming. FP has a strong mathematical foundation based on lambda calculations.
 
The one thing that functional programming does well is it helps us write reliable software, and the need for a debugger almost disappears.

Functional programming uses abstract mathematics (algebra, logic); and, if you do everything pure and clean, then you can even write a mathematical proof that your source code fulfills a specific formal specification. I am like most of you, an imperative programmer. The problem is, I have learned functional programming concepts several times, but by the time I need it I have forgotten the most stuff because I do not practice it.
 
I have decided to learn Functional Programming in an innovative way. I will use a non-pure functional programming language, and I will create a desktop business domain application just like what we do with C#, and step by step, convert it to a clean functional style. In this way, I will not forget what I did, and I can also use it in my daily job.
 
In this article, I have written my experience with F#, and I hope this article can motivate you to write more functional code.

“F# is a simple and expressive programming language. It can be described as statically typed impure functional language that supports functional, imperative, and object-oriented paradigm and also several other programming styles, including data-driven, event-driven, and parallel programming.”
 
The Customers Demo application.
 
Source Code on Github.
 
Or you can download it from here.
 
Prerequisite
 
Visual Studio 2019 and Microsoft SQL Server Express
 
Step 1
 
I have created an F# Visual Studio project as below.
 
Easy Way To Become An F# Programmer For C# Developers
 
The generated Program.fs,
  1. open System  
  2.   
  3. [<EntryPoint>]  
  4. let main argv =  
  5.   
  6. printfn "Hello World from F#!"  
  7. // return an integer exit code  
If you press F5, then you can see the Hello World from F#! in the console.
 
Step 2
 
I have added two libraries — one to access the database and the other one for the user interface based on WPF.
 
In the Package Manager Console,
  1. Install-Package SQLProvider -Version 1.1.68  
  2. Install-Package FSharp.Desktop.UI -Version 0.7.1 
Easy Way To Become An F# Programmer For C# Developers
 
Step 3
 
I have added the domain entity (Domain.fs) as below.

Customer class has two properties: CustomerId and Name.
  1. module Domain  
  2.   
  3. type Customer(customerId:int, name:string) =   
  4. inherit FSharp.Desktop.UI.Model()  
  5.   
  6. let mutable customerId =customerId   
  7. let mutable name = name  
  8.   
  9. member this.CustomerId  
  10. with get() = customerId  
  11. and set value =   
  12. customerId <- value  
  13. this.NotifyPropertyChanged "CustomerId"  
  14.   
  15. member this.Name  
  16. with get() = name  
  17. and set value =   
  18. name <- value  
  19. this.NotifyPropertyChanged "Name"  
Step 4
 
I need to store/load the customer to/from the database, so I have defined my database context in the DataContext.
  1. module DataContext  
  2.   
  3. open FSharp.Data.Sql  
  4. open Microsoft.FSharp.Collections  
  5.   
  6. [<Literal>]  
  7. let connectionString = "Server=.\SQLExpress; Database=ShopDatabase;   
  8. Trusted_Connection=true;"  
  9.   
  10. type Sql = SqlDataProvider<Common.DatabaseProviderTypes.MSSQLSERVER, connectionString>  
  11.   
  12. let DbContext = Sql.GetDataContext()  
  13.   
  14. let FirstCustomer =   
  15.              query {  
  16.                        for customer in DbContext.Dbo.Customers do  
  17.                        select customer   
  18.                        } |> Seq.head;  
  19.   
  20. let GetNextCustomer (id) =   
  21.             query {  
  22.                       for customer in DbContext.Dbo.Customers do  
  23.                       where (customer.CustomerId >id)  
  24.                       select customer  
  25.                      } |> Seq.tryHead  
  26.   
  27. let GetBeforeCustomer (id) =  
  28.             query {  
  29.                       for customer in DbContext.Dbo.Customers do  
  30.                       where (customer.CustomerId < id)  
  31.                       select customer  
  32.                      } |> Seq.tryLast  
Step 5
 
I have created and seeded the database with the help of SQL Server Management Studio.
 
Easy Way To Become An F# Programmer For C# Developers 
 
The SQL Script,
  1. USE master;  
  2. GO  
  3.   
  4. IF DB_ID (N'ShopDatabase'IS NOT NULL  
  5. DROP DATABASE ShopDatabase;  
  6. GO  
  7.   
  8. CREATE DATABASE ShopDatabase;  
  9. GO  
  10.   
  11. Use ShopDatabase  
  12. GO  
  13.   
  14. CREATE TABLE Customers (  
  15. CustomerId INT PRIMARY KEY,  
  16. Name nvarchar(25));  
  17. GO  
  18.   
  19. INSERT INTO Customers(CustomerId, Name)  
  20. VALUES (1, 'Bassam'), (2,'Mays'), (3,'Rami'), (4,'Fadi'), (5,'Alugili');  
Step 6
 
I have used FSharp.Desktop.UI to display the data.
 
„FSharp.Desktop.UI designed for building WPF applications in F#. With strong support for MVC, functional, asynchronous, and event-driven programming, it will enable you to build your solution quickly, without the need to sacrifice type system or testability.”
 
Easy Way To Become An F# Programmer For C# Developers
 
The main view contains the view logic. I have added in the grid the main panel and two textboxes and two buttons and some labels, and I have also registered some events like Button Click/ MouseWheel / Key Up/Down.
  1. module MainView  
  2.   
  3. open FSharp.Desktop.UI  
  4. open System.Windows  
  5. open System.Windows.Controls  
  6. open System.Windows.Input  
  7. open System.Windows.Data  
  8. open System.Windows.Media;  
  9.   
  10. type NumericUpDownEvents = Up | Down  
  11.   
  12. type MainView() as this =   
  13. inherit View<UpDownEvents, Domain.Customer, Window>(Window())   
  14.   
  15. //Assembling WPF window in code.   
  16. do   
  17. this.Root.Width <- 800.  
  18. this.Root.Height <- 600.  
  19. this.Root.WindowStartupLocation <- WindowStartupLocation.CenterScreen  
  20. this.Root.Title <- "F# Desktop Demo Application"  
  21. this.Root.Background <- Brushes.LightCyan  
  22.   
  23. let mainPanel =   
  24. let grid = Grid(HorizontalAlignment = HorizontalAlignment.Stretch, VerticalAlignment = VerticalAlignment.Stretch, ShowGridLines = true)  
  25. [ RowDefinition(Height= GridLength(300.)); RowDefinition(Height= GridLength(300.)) ] |> List.iter grid.RowDefinitions.Add   
  26. [ ColumnDefinition(Width= GridLength(300.)); ColumnDefinition(Width= GridLength(300.));ColumnDefinition(Width= GridLength(200.)) ] |> List.iter grid.ColumnDefinitions.Add  
  27. grid  
  28.   
  29. let idLabel = Label(Content= "Id: ", FontSize = 20., Width = 150., HorizontalAlignment = HorizontalAlignment.Left, VerticalAlignment = VerticalAlignment.Top);  
  30.   
  31. let userIdTextBox = TextBox(FontSize = 20., Width = 150., Height = 50., HorizontalAlignment = HorizontalAlignment.Left, VerticalAlignment = VerticalAlignment.Top, Background = Brushes.LightBlue)  
  32.   
  33. let userNameLabel = Label(Content= "Name: ", FontSize = 20., Width = 150., HorizontalAlignment = HorizontalAlignment.Left, VerticalAlignment = VerticalAlignment.Top)  
  34.   
  35. let userNameTextBox = TextBox(FontSize = 20., Width = 150., Height = 50., HorizontalAlignment = HorizontalAlignment.Left, VerticalAlignment = VerticalAlignment.Top, Background = Brushes.LightBlue)  
  36.   
  37. let upButton = Button(Content = "^", FontSize = 20., Width = 150., Height = 50., Background = Brushes.LightCyan)  
  38.   
  39. let downButton = Button(Content = "v", FontSize = 20.,Width = 150., Height = 50.,Background = Brushes.LightCyan)  
  40.   
  41. do   
  42. Grid.SetRow(idLabel,0)  
  43. Grid.SetColumn(idLabel,0)  
  44. Grid.SetRow(userIdTextBox,0)  
  45. Grid.SetColumn(userIdTextBox, 1)  
  46. Grid.SetRow(userNameLabel, 1)  
  47. Grid.SetColumn(userNameLabel, 0)  
  48. Grid.SetRow(userNameTextBox, 1)  
  49. Grid.SetColumn(userNameTextBox, 1)  
  50. Grid.SetRow(upButton, 0)  
  51. Grid.SetColumn(upButton, 2)  
  52. Grid.SetRow(downButton, 1)  
  53. Grid.SetColumn(downButton, 2)  
  54.   
  55. mainPanel.Children.Add idLabel |> ignore  
  56. mainPanel.Children.Add userIdTextBox |> ignore  
  57. mainPanel.Children.Add userNameLabel |> ignore  
  58. mainPanel.Children.Add userNameTextBox |> ignore  
  59. mainPanel.Children.Add upButton |> ignore  
  60. mainPanel.Children.Add downButton |> ignore  
  61.   
  62. this.Root.Content <- mainPanel  
  63.   
  64. //View implementation   
  65. override this.EventStreams = [  
  66. upButton.Click |> Observable.map (fun _ -> Up)  
  67. downButton.Click |> Observable.map (fun _ -> Down)  
  68. userIdTextBox.KeyUp |> Observable.choose (fun args ->   
  69. match args.Key with   
  70. | Key.Up -> Some Up   
  71. | Key.Down -> Some Down  
  72. | _ -> None  
  73. )  
  74. userIdTextBox.MouseWheel |> Observable.map (fun args -> if args.Delta > 0 then Up else Down)  
  75. ]  
  76. override this.SetBindings model =   
  77. Binding.OfExpression   
  78. <@  
  79. userIdTextBox.Text <- coerce model.CustomerId   
  80. userNameTextBox.Text <- coerce model.Name   
  81. @>  
Step 7
 
I have created a controller to separate the presentation logic from the business logic — the trick here in the UpDownEvents. When any button or key is pressed or you move the mouse wheel up/down in the Textbox, then I am firing in the View an up or down event. I am listing those events in the controller and retrieving the data from the database, as shown below.
  1. module Controller  
  2.   
  3. let eventHandler event (customer: Domain.Customer) =  
  4.               match event with  
  5. | MainView.Up ->   
  6. let nextCustomer = DataContext.GetNextCustomer customer.CustomerId  
  7.               match nextCustomer with   
  8.               | Some c -> customer.CustomerId <- c.CustomerId  
  9.                                 customer.Name <- c.Name   
  10.               | None -> customer.CustomerId <- 0  
  11.                              customer.Name <- "Not found upper!"   
  12.   
  13. | MainView.Down ->  
  14. let beforeCustomer = DataContext.GetBeforeCustomer customer.CustomerId  
  15.               match beforeCustomer with   
  16.             | Some c -> customer.CustomerId <- c.CustomerId  
  17.                               customer.Name <- c.Name   
  18.             | None -> customer.CustomerId <- 0  
  19.                            customer.Name <- "Not found down!"
Step 8
 
Finally, we have to wire the modules. I did that in the Program.fs
  1. open System  
  2. open System.Windows  
  3. open FSharp.Desktop.UI  
  4.   
  5. [<STAThread>]  
  6. // Learn more about F# at http://fsharp.org  
  7.   
  8. [<EntryPoint>]  
  9. do  
  10. let firstCustomer = DataContext.FirstCustomer  
  11.   
  12. // Create a Customer Model instance.  
  13. let customerModel = Domain.Customer.Create(firstCustomer.CustomerId, firstCustomer.Name)  
  14.   
  15. let view = MainView.MainView()  
  16.   
  17. let controller:IController<MainView.UpDownEvents, Domain.Customer> = Controller.Create Controller.eventHandler  
  18.   
  19. let mvc = Mvc(customerModel, view,controller)  
  20. use eventLoop = mvc.Start()  
  21. Application().Run( window = view.Root) |> ignore  
Your application should be like below,
 
Easy Way To Become An F# Programmer For C# Developers
 
Press F5 and enjoy your first F# application😊
 
Easy Way To Become An F# Programmer For C# Developers
 
You can click on the up/down buttons to browse the data, or you can do that by using the arrow keys up/down or the Mouse wheel.
 
The application is ready to use. The next question is, what we can do it better in this application?

The first problem: We have used the mutable keyword.
  1. let mutable customerId =customerId   
  2. let mutable name = name  
The mutable state belongs to the imperative programming style. Can we change that?
 
The second problem: This query throws an exception if the database does not exist or is empty. Exceptions in functional programming are not desired. Can we make it better? A tip looks to tryHead.
  1. let FirstCustomer = query {  
  2.     for customer in DbContext.Dbo.Customers do  
  3.     select customer   
  4. } |> Seq.head;

Summary

 
Good developers must know more than one programming paradigm. One of the best choices is the functional programming paradigm. FP makes you a powerful programmer, and it allows you to solve complex problems more cleanly. Remember your salary depends on your knowledge and skills, if you can do more then the other developers, then you can negotiate a higher salary by showing that you have been valuable to the company.
 
In this article, we have created an F# Desktop application, and I have shown you how easily we can create a desktop application with F# for C# programmers. We have created a domain application, and in the next part, I will do more business models and business logic. Please leave a comment if you enjoyed my article. 


Similar Articles