﻿ F# Topics: Composing Functions
 F# Topics: Composing Functions

 Introduction
 Imagine you have two or more functions in a program: the functions take the same number and type(s) of argument(s); the assignment(s) performed by one (or more) of the function(s) can be used by another function. For example, consider the area of a circle. It is calculated as Radius2 * PI (which is approximately 3.14156...). The area of a sphere is gotten by simply multiplying the area of a circle by 4 (4 * Radius2 * PI). If you already have a function that calculates the area of a circle, you can simply "add" it to another simpler function to get the area of a sphere.

You can "add" one function to another. This is referred to as composing the functions. First, you must define the functions. Here are examples:

let PI = 3.14156

let calculateCircleArea radius = radius * radius * PI
let multiplyBy4 value = 4.00 * value // Area of a Sphere

To compose two functions, you use the >> or the << operator. As mentioned in the beginning, composed functions use the same number and type(s) of argument(s). To get the result of composing the functions, you must provide the argument(s) to the composition. You have various options. If you want to immediately use the result of the composition, you can include the operation in parentheses followed by the argument(s). Here is an example:

open System
open System.Windows.Forms

// Form: Geometry - Sphere
let sphere : Form = new Form()
sphere.Width  <- 285
sphere.Height <- 170
sphere.Text <- "Geometry - Sphere"

// Label: Radius
let lblRadius : Label = new Label()
lblRadius.Left  <- 22
lblRadius.Top   <- 19
lblRadius.Width <- 80
lblRadius.Text  <- "Radius:"
sphere.Controls.Add lblRadius

// Text Box: Radius
let txtRadius : TextBox = new TextBox()
txtRadius.Left  <- 105
txtRadius.Top   <- 16
txtRadius.Width <- 74
txtRadius.Text  <- "0.00"
sphere.Controls.Add txtRadius

// Button: Calculate
let btnCalculate : Button = new Button()
btnCalculate.Left <- 186
btnCalculate.Top  <-  16
btnCalculate.Text <- "Calculate"

// Label: Diameter
let lblDiameter : Label = new Label()
lblDiameter.Left  <- 22
lblDiameter.Top   <- 53
lblDiameter.Width <- 80
lblDiameter.Text  <- "Diameter:"
sphere.Controls.Add lblDiameter

// Text Box: Diameter
let txtDiameter : TextBox = new TextBox()
txtDiameter.Left  <- 105
txtDiameter.Top   <- 50
txtDiameter.Width <- 74
sphere.Controls.Add txtDiameter

// Label: Surface Area
let lblSurfaceArea : Label = new Label()
lblSurfaceArea.Left  <- 22
lblSurfaceArea.Top   <- 82
lblSurfaceArea.Width <- 80
lblSurfaceArea.Text  <- "Surface Area:"
sphere.Controls.Add lblSurfaceArea

// Text Box: Surface Area
let txtSurfaceArea : TextBox = new TextBox()
txtSurfaceArea.Left  <- 105
txtSurfaceArea.Top   <- 80
txtSurfaceArea.Width <- 74
sphere.Controls.Add txtSurfaceArea

// Label: Volume
let lblVolume : Label = new Label()
lblVolume.Left  <-  22
lblVolume.Top   <- 110
lblVolume.Width <-  80
lblVolume.Text  <- "Volume:"
sphere.Controls.Add lblVolume

// Text Box: Volume
let txtVolume : TextBox = new TextBox()
txtVolume.Left  <- 105
txtVolume.Top   <- 110
txtVolume.Width <-  74
sphere.Controls.Add txtVolume

// Button: Close
let btnClose : Button = new Button()
btnClose.Left  <- 186
btnClose.Top   <- 108
btnClose.Text <- "Close"

let btnCloseClick _ = sphere.Close()
btnClose.Click.Add btnCloseClick
sphere.Controls.Add btnClose

let PI = 3.14156
let calculateCircleDiameter radius = radius * 2.00

let calculateCircleArea radius = radius * radius * PI
let multiplyBy4 value = 4.00 * value // Area of a Sphere

let btnCalculateClick e =
let radius     = float txtRadius.Text
let diameter   = calculateCircleDiameter <| radius
let circleArea = calculateCircleArea <| radius
let sphereArea = (calculateCircleArea << multiplyBy4) radius
let volume     = multiplyBy4 <| radius

let strDiameter = sprintf "%f" diameter
let strSphereArea = sprintf "%f" sphereArea
let strVolume   = sprintf "%f" volume

txtDiameter.Text    <- strDiameter
txtSurfaceArea.Text <- strSphereArea
txtVolume.Text      <- strVolume

btnCalculate.Click.Add btnCalculateClick
sphere.Controls.Add btnCalculate

Application.Run sphere

Here is an example of running the program:

Another option is to assign the composition without the argument(s) to a function value. Here is an example:

let area = calculateCircleArea << multiplyBy4

Then, to use the result of the composition, call the function and pass the desired value(s). Here is an example:

let PI = 3.14156
let calculateCircleArea radius = radius * radius * PI
let calculateCircleDiameter radius = radius * 2.00
let multiplyBy4 value = 4.00 * value // Area of a Sphere

let btnCalculateClick e =
let radius     = float txtRadius.Text
let diameter   = calculateCircleDiameter <| radius
let circleArea = calculateCircleArea <| radius
let sphereArea = calculateCircleArea << multiplyBy4
let volume     = multiplyBy4 <| radius

let strDiameter = sprintf "%f" diameter
let strSphereArea = sprintf "%f" (sphereArea radius)
let strVolume   = sprintf "%f" volume

txtDiameter.Text    <- strDiameter
txtSurfaceArea.Text <- strSphereArea
txtVolume.Text      <- strVolume

As mentioned already, when composing two functions, you place one function to the left of << or >> and one function to the right of << or >>:

• If you use the << operator, the function on the left side would execute first. Here is an example:
let PI = 3.14156;

let calculateCircleArea radius = radius * radius * PI;
let multiplyBy4 value = 4.00 * value; // Area of a Sphere

let area = calculateCircleArea << multiplyBy4
let result = area 25.85
• If you use the >> operator, the function on the right side would execute first. Here is an example:
let greetings msg = msg + " - F# is fun!"
let define    msg = "Announcement: " + msg
let combine = define >> greetings

let g = combine "Welcome to the wonderful world of functional programming"

sprintf "%s" g

 Composing Many Functions

In the same way, you can compose as many functions as you want. Here is an example with three functions:

open System
open System.Windows.Forms

let exercise : Form = new Form()
exercise.Width <- 235
exercise.Height <- 108
exercise.Text <- "Salary Evaluation"

let lblHourlySalary : Label = new Label()
lblHourlySalary.Left <- 12
lblHourlySalary.Top <- 22
lblHourlySalary.Width <- 82
lblHourlySalary.Text <- "Hourly Salary:"
exercise.Controls.Add(lblHourlySalary)

let txtHourlySalary : TextBox = new TextBox()
txtHourlySalary.Left <- 95
txtHourlySalary.Top <- 18
txtHourlySalary.Width <- 40
txtHourlySalary.Text <- "0"
exercise.Controls.Add(txtHourlySalary)

let lblYearlySalary : Label = new Label()
lblYearlySalary.Left <- 12
lblYearlySalary.Top <- 45
lblYearlySalary.Width <- 82
lblYearlySalary.Text <- "Yearly Salary:"
exercise.Controls.Add(lblYearlySalary)

let txtYearlySalary : TextBox = new TextBox()
txtYearlySalary.Left <- 95
txtYearlySalary.Top <- 45
txtYearlySalary.Width <- 110
txtYearlySalary.Text <- "0"
exercise.Controls.Add(txtYearlySalary)

let btnCalculate : Button = new Button()
btnCalculate.Left <- 140
btnCalculate.Top <- 16
btnCalculate.Width <- 65
btnCalculate.Text <- "Calculate"

let btnCalculateClick e =
let hourlySalary = float txtHourlySalary.Text

let EvaluateDailySalary salary = salary * 8.00  // Daily Salary   = Hourly Salary * 8
let multiplBy20 value = value * 20.00           // Monthly Salary = Daily Salary * 20
let multiplBy12 value = value * 12.00           // Yearly Salary  = Monthly Salary * 12

let yearEvaluation = EvaluateDailySalary >> multiplBy20 >> multiplBy12
let yearlySalary = yearEvaluation hourlySalary

txtYearlySalary.Text <- string yearlySalary
btnCalculate.Click.Add btnCalculateClick
exercise.Controls.Add btnCalculate

Application.Run exercise

Here is an example of executing the program:

Here is an example with five functions:

let btnCalculateClick e =
let hourlySalary = float txtHourlySalary.Text

// Daily Salary   = Hourly Salary * 8
let EvaluateDailySalary salary = salary * 8.00
// Weekly Salary = Daily Salary * 5
let multiplBy5 value = value * 5.00
// Bi-Monthly Salary = Weekly Salary * 2
// Monthly Salary = Bi-Monthly Salary * 2
let multiplBy2 value = value * 2.00
// Yearly Salary  = Monthly Salary * 12
let multiplBy12 value = value * 12.00

let yearEvaluation = EvaluateDailySalary >> multiplBy5 >> multiplBy2 >> multiplBy2 >> multiplBy12
let yearlySalary = yearEvaluation hourlySalary

txtYearlySalary.Text <- string yearlySalary

When composing many functions, to make your code easy to ready, you can put them on different lines with appropriate indentation. Here is an example:

let btnCalculateClick e =
let hourlySalary = float txtHourlySalary.Text

// Daily Salary   = Hourly Salary * 8
let EvaluateDailySalary salary = salary * 8.00
// Weekly Salary = Daily Salary * 5
let multiplBy5 value = value * 5.00
// Bi-Monthly Salary = Weekly Salary * 2
// Monthly Salary = Bi-Monthly Salary * 2
let multiplBy2 value = value * 2.00
// Yearly Salary  = Monthly Salary * 12
let multiplBy12 value = value * 12.00

let yearEvaluation = EvaluateDailySalary
>> multiplBy5
>> multiplBy2
>> multiplBy2
>> multiplBy12
let yearlySalary = yearEvaluation hourlySalary

txtYearlySalary.Text <- string yearlySalary

 Home Copyright © 2009-2015, FunctionX Home