Home

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:

Lambda Expressions

Lambda Expressions

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:

Integral Variables

Integral Variables

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