Home

Topics on Functions

 

Fundamentals of Functions

 

The Return Type of a Function

When a function has performed its assignment, it may or may not produce a value. If a function produces a value, that function is said to return a value. If you create a function and appropriately define it, the compiler will try to find out the type of value the function must return. In some cases, you may want to specify the type of value that a function must return. To specify the return type, before the = sign, type a colon followed by the desired data type. Here is an example:

 
let getValue() : int =
    1450

Do the same even if the function takes more than one parameter. Here is an example:

let getFullName first_name middle_initial last_name : string =
    first_name + " " + middle_initial + ". " + last_name

If you specify the data type(s) of the parameter(s) and you want to indicate the return type of the function, specify it after the parentheses of the (last) parameter. Here is an example:

let add (x:int) (y:int) (z:int) : int = x + y + y

Techniques of Returning a Value

Consider the following function:

let calculate x y z = x + y + y

If a function has only one statement in its body, that statement produces the value that the function returns. In the above case, the function returns the value that would be produced by the expression x + y + z. As mentioned previously, the body of a function can start and/or end on a line other than the one with the = sign. Here is an example:

let calculate x y z =
    x + y + y;

Still, in this case, the return value is the one produced by x + y + z.

In some cases, before giving its last expression, the body of a function may contain multiple statements. Here is an example:

let calculate x y z =
    sprintf "Number 1: %d" x
    sprintf "Number 2: %d" y
    sprintf "Number 3: %d" z
    x + y + y

In this case also, the last expression constitutes the return value of the function.

A Function in a Function

One of the characteristics of functional programming is that a function can be created in the body of another function. Here are examples:

open System
open System.Windows.Forms

let create caption =
    let calculateValueOfAnnuity yearlyDeposit interestRate periods =
        let interestPercent = interestRate / 100.00
        let interestPlus1 = 1.00 + interestPercent
        let poweredInterest = interestPlus1 ** periods
        let poweredInterestMinus1 = poweredInterest - 1.00
        yearlyDeposit * poweredInterestMinus1 / interestPercent
    let calculateInterestEarned futureValue deposit periods =
        let deposits = deposit * periods
        futureValue - deposits

    // Form: Future Value of an Ordinary Annuity
    let ordinaryAnnuity : Form = new Form()
    ordinaryAnnuity.Width  <- 288
    ordinaryAnnuity.Height <- 210
    ordinaryAnnuity.Text <- caption

    // Label: Yearly Deposit
    let lblYearlyDeposit : Label = new Label()
    lblYearlyDeposit.Left <- 18
    lblYearlyDeposit.Top  <- 24
    lblYearlyDeposit.Width <- 85
    lblYearlyDeposit.Text <- "Yearly Deposit:"
    ordinaryAnnuity.Controls.Add lblYearlyDeposit

    // Text Box: PurchasePrice
    let txtYearlyDeposit : TextBox = new TextBox()
    txtYearlyDeposit.Left  <- 106
    txtYearlyDeposit.Top   <- 21
    txtYearlyDeposit.Width <- 60
    txtYearlyDeposit.Text  <- "0.00"
    ordinaryAnnuity.Controls.Add txtYearlyDeposit

    // Label: Interest Rate
    let lblInterestRate : Label = new Label()
    lblInterestRate.Left  <- 18
    lblInterestRate.Top   <- 55
    lblInterestRate.Width <- 85
    lblInterestRate.Text  <- "Interest Rate:"
    ordinaryAnnuity.Controls.Add lblInterestRate

    // Text Box: Interest Rate
    let txtInterestRate : TextBox = new TextBox()
    txtInterestRate.Left <- 106
    txtInterestRate.Top <- 51
    txtInterestRate.Width <- 44
    txtInterestRate.Text <- "0.00"
    ordinaryAnnuity.Controls.Add txtInterestRate

    // Label: Percent %
    let lblPercent : Label = new Label()
    lblPercent.Left  <-  150
    lblPercent.Top   <-  55
    lblPercent.Width <-  60
    lblPercent.Text  <- "%"
    ordinaryAnnuity.Controls.Add lblPercent

    // Label: Periods
    let lblPeriods : Label = new Label()
    lblPeriods.Left  <-  18
    lblPeriods.Top   <-  82
    lblPeriods.Width <-  68
    lblPeriods.Text  <- "Periods:"
    ordinaryAnnuity.Controls.Add lblPeriods

    // Text Box: Periods
    let txtPeriods : TextBox = new TextBox()
    txtPeriods.Left  <- 106
    txtPeriods.Top   <-  81
    txtPeriods.Width <-  44
    txtPeriods.Text  <- "0.00"
    ordinaryAnnuity.Controls.Add txtPeriods

    // Label: Years
    let lblYears : Label = new Label()
    lblYears.Left  <-  150
    lblYears.Top   <-   85
    lblYears.Width <-   36
    lblYears.Text  <- "Years"
    ordinaryAnnuity.Controls.Add lblYears

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

    // Label: Future Value
    let lblFutureValue : Label = new Label()
    lblFutureValue.Left  <-   18
    lblFutureValue.Top   <-  118
    lblFutureValue.Width <-  80
    lblFutureValue.Text  <- "Future Value:"
    ordinaryAnnuity.Controls.Add lblFutureValue

    // Text Box: Future Value
    let txtFutureValue : TextBox = new TextBox()
    txtFutureValue.Left  <- 106
    txtFutureValue.Top   <- 115
    txtFutureValue.Width <-  64
    txtFutureValue.Text  <- "0.00"
    ordinaryAnnuity.Controls.Add txtFutureValue

    // Label: Interest Earned
    let lblInterestEarned : Label = new Label()
    lblInterestEarned.Left  <-  18
    lblInterestEarned.Top   <-  145
    lblInterestEarned.Width <-  88
    lblInterestEarned.Text  <- "Interest Earned:"
    ordinaryAnnuity.Controls.Add lblInterestEarned

    // Text Box: Interest Earned
    let txtInterestEarned : TextBox = new TextBox()
    txtInterestEarned.Left  <- 106
    txtInterestEarned.Top   <-  142
    txtInterestEarned.Width <-  64
    txtInterestEarned.Text  <- "0.00"
    ordinaryAnnuity.Controls.Add txtInterestEarned

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

    let btnCalculateClick e =
        let principal   = float txtYearlyDeposit.Text
        let intRate     = float txtInterestRate.Text
        let years       = float txtPeriods.Text
        let futureValue = calculateValueOfAnnuity principal intRate years
        let earned      = calculateInterestEarned futureValue principal years
        
        let strFutureValue = sprintf "%0.02f" futureValue
        let strInterestEarned = sprintf "%0.02f" earned
        
        txtFutureValue.Text <- strFutureValue
        txtInterestEarned.Text <- strInterestEarned
    btnCalculate.Click.Add btnCalculateClick
    ordinaryAnnuity.Controls.Add btnCalculate

    let btnCloseClick e = ordinaryAnnuity.Close()
    btnClose.Click.Add btnCloseClick
    ordinaryAnnuity.Controls.Add btnClose

    Application.Run ordinaryAnnuity

create "Future Value of Ordinary Annuity"

Here is an example of executing the program:

A Function in a Function

A Function in a Function

Automatic Generalization

Remember that you can pass a parameter to a function without specifying the data type of that parameter, in which case the compiler would consider that the parameter uses an integer value. We also saw that the way a parameter is used, whether in the function's body or when the function is called, can specify the actual value of the parameter. This is also valid if the function takes more than one parameter. This is referred to as automatic generalization.

     

Functions in a Variable

Like many languages, F# wants you to initialize a variable when declaring it. Like most languages, F# allows you initialize a variable by calling a function, that is, by using the return value of a function. Unlike many languages, F# allows you to create one or many expressions by which you would get a value for the variable. For example, you can declare variables, call functions, and create a value that the variable would use. Here is an example:

let totalArea =
    let length = 36.88
    let width  = 27.99
    let height = 12.74
    let side1 = multiply length width
    let side2 = multiply length height
    let side3 = multiply width height

When you do this, the variable behaves like a function: the last line would hold the value that will be given to the variable. Here is an example:

let multiply x y = x * y

let totalArea =
    let length = 36.88
    let width  = 27.99
    let height = 12.74
    let side1 = multiply length width
    let side2 = multiply length height
    let side3 = multiply width height
    side1 + side2 + side3

sprintf "Total Box Area: %0.04f"  totalArea

You can then use the variable as you want. Here is an example:

open System
open System.Windows.Forms

let subtract a b = a - b
let divide   a b : float = a / b

// Form: Depreciation - Straight-Line Method
let depreciationSLM : Form = new Form()
depreciationSLM.Width  <- 295
depreciationSLM.Height <- 170
depreciationSLM.Text <- "Depreciation - Straight-Line Method"

// Label: Cost
let lblCost : Label = new Label()
lblCost.Left  <- 22
lblCost.Top   <- 19
lblCost.Width <- 80
lblCost.Text  <- "Cost:"
depreciationSLM.Controls.Add lblCost

// Text Box: Machine Cost
let txtCost : TextBox = new TextBox()
txtCost.Left  <- 105
txtCost.Top   <- 16
txtCost.Width <- 54
depreciationSLM.Controls.Add txtCost

// Label: Salvage Value
let lblSalvageValue : Label = new Label()
lblSalvageValue.Left  <- 22
lblSalvageValue.Top   <- 45
lblSalvageValue.Width <- 80
lblSalvageValue.Text  <- "Salvage Value:"
depreciationSLM.Controls.Add lblSalvageValue

// Text Box: SalvageValue
let txtSalvageValue : TextBox = new TextBox()
txtSalvageValue.Left  <- 105
txtSalvageValue.Top   <- 43
txtSalvageValue.Width <- 54
depreciationSLM.Controls.Add txtSalvageValue

// Label: Estimated Life
let lblEstimatedLife : Label = new Label()
lblEstimatedLife.Left  <- 22
lblEstimatedLife.Top   <- 74
lblEstimatedLife.Width <- 80
lblEstimatedLife.Text  <- "Estimated Life:"
depreciationSLM.Controls.Add lblEstimatedLife

// Text Box: Estimated Life
let txtEstimatedLife : TextBox = new TextBox()
txtEstimatedLife.Left  <- 105
txtEstimatedLife.Top   <- 70
txtEstimatedLife.Width <- 34
depreciationSLM.Controls.Add txtEstimatedLife

// Label: Years
let lblYears : Label = new Label()
lblYears.Left  <- 142
lblYears.Top   <-  76
lblYears.Width <-  40
lblYears.Text  <- "Years"
depreciationSLM.Controls.Add lblYears

// Button: Calculate
let btnCalculate : Button = new Button()
btnCalculate.Left <- 196
btnCalculate.Top  <-  71
btnCalculate.Text <- "Allocate"

// Label: Depreciation
let lblDepreciation : Label = new Label()
lblDepreciation.Left  <-  22
lblDepreciation.Top   <- 108
lblDepreciation.Width <-  74
lblDepreciation.Text  <- "Depreciation:"
depreciationSLM.Controls.Add lblDepreciation

// Text Box: Depreciation
let txtDepreciation : TextBox = new TextBox()
txtDepreciation.Left  <- 105
txtDepreciation.Top   <- 105
txtDepreciation.Width <- 54
depreciationSLM.Controls.Add txtDepreciation

// Label: /Years
let lblPerYear : Label = new Label()
lblPerYear.Left  <- 162
lblPerYear.Top   <- 106
lblPerYear.Width <-  34
lblPerYear.Text  <- "/Year"
depreciationSLM.Controls.Add lblPerYear

// Button: Close
let btnClose : Button = new Button()
btnClose.Left  <- 196
btnClose.Top   <- 104
btnClose.Text <- "Close"
let btnCloseClick e =  depreciationSLM.Close()
btnClose.Click.Add btnCloseClick
depreciationSLM.Controls.Add btnClose

let btnCalculateClick e =
    let depreciation =
        let cost  = float txtCost.Text
        let value = float txtSalvageValue.Text
        let life  = float txtEstimatedLife.Text

        let numerator = subtract cost value
        divide numerator life

    let strDepreciation = sprintf "%0.02f" depreciation
    txtDepreciation.Text <- strDepreciation

btnCalculate.Click.Add btnCalculateClick
depreciationSLM.Controls.Add btnCalculate

Application.Run depreciationSLM

Here is an eample of running the program:

Functions in a Variable

Functions in a Variable

The Signature of a Function

The signature of a function is a technique of indicating its arguments and its return type. The basic formula of a function signature is:

function-name : parameter-type(s) -> return-type

The signature starts with the name of the function. This is followed by a colon. If the function takes one argument, specify its type. This is followed by -> and the data type of the value the function returns. Here is an example:

calculateSquareArea : float -> float

This means that we are using a function named calculateSquareArea. The function takes one argument that is a decimal number. The function returns a decimal number.

Here is how to specify or read the signature of a function:

  • If the function doesn't take any argument, in which case it may have empty parentheses, specify its parameter-type as unit. This would be done as follows:
    presentGreetings : unit -> return-type
  • If the function doesn't return a value, specify its return-type as unit. This would be done as follows:
    presentGreetings : parameter-type(s) -> unit
  • If the function takes more than one argument, in the parameter-type(s) placeholder, specify the data type of each argument but separate them with ->. Here is one example:
    calculateCylinderVolume : float -> float -> float
    This indicates that we have a function named calculateCylinderVolume. The function takes two arguments of type float. The function returns a floating-point number. Here another example:
    showStudentRecord : string -> int -> unit
    This indicates that we have a function named showStudentRecord. The function takes two arguments. The first argument is a string. The second argument is a character. The function doesn't return a known value

A Variable as a Function

When you assign a lambda expression to a variable, the variable becomes a function, or you can use this characteristic to declare a variable and assign a lambda expression to it without specifying the that will be processed. Here is an example:

 let grossSalary = (fun units ->
    if units <= 100.00 then units * 2.25
    elif units <= 250.00 then
        let first100 = 100.00 * 2.45
        let others = (units - 100.00) * 2.25
        first100 + others
    else
        let first100 = 100.00 * 2.25
        let between100And250 = 150.00 * 2.45
        let others = (units - 250.00) * 2.68
        first100 + between100And250 + others)

To treat the variable as a function, assign it to another variable and pass the appropriate value(s), the same way it would be done when calling a normal function. Here is an example:

let btnCalculateClick(e) =
    let items = float txtUnits.Text

    let grossSalary = (fun units ->
        if units <= 100.00 then units * 2.25
        elif units <= 250.00 then
            let first100 = 100.00 * 2.45
            let others = (units - 100.00) * 2.25
            first100 + others
        else
            let first100 = 100.00 * 2.25
            let between100And250 = 150.00 * 2.45
            let others = (units - 250.00) * 2.68
            first100 + between100And250 + others)
    
    let wages = grossSalary items
    txtGrossSalary.Text <- sprintf "%0.02f" wages

In the same way, if the lambda expression is made to process many values, pass them as arguments to the variable. Here are example:

let btnCalculateClick(e) =
    let weeklySales = float txtWeeklySales.Text
    let commissionRate = float txtCommissionRate.Text
    
    let commissionAmount = fun x y -> x * y / 100.00
    let payment = commissionAmount weeklySales commissionRate

    let strCommissionAmount = sprintf "%0.02f" payment
    txtCommissionAmount.Text <- strCommissionAmount

Another option is to create the lambda expression where it is needed. In this case, the expression must be included in parentheses. Here is an example:

let btnCalculateClick(e) =
    let items = float txtUnits.Text
        
    txtGrossSalary.Text <- sprintf "%0.02f" ((fun units ->
            if units <= 100.00 then units * 2.25
            elif units <= 250.00 then
                let first100 = 100.00 * 2.45
                let others = (units - 100.00) * 2.25
                first100 + others
            else
                let first100 = 100.00 * 2.25
                let between100And250 = 150.00 * 2.45
                let others = (units - 250.00) * 2.68
                first100 + between100And250 + others) items)

Or like this:

let btnCalculateClick e =
    let weeklySales = float txtWeeklySales.Text
    let commissionRate = float txtCommissionRate.Text
        
    let strCommissionAmount = sprintf "%0.02f" ((fun x y -> x * y / 100.00) weeklySales commissionRate)
    txtCommissionAmount.Text <- strCommissionAmount

Or like this:

let btnCalculateClick(e) =
    let strCommissionAmount = sprintf "%0.02f" ((fun x y -> x * y / 100.00) (float txtWeeklySales.Text) (float txtCommissionRate.Text))
    txtCommissionAmount.Text <- strCommissionAmount

Or like this:

let btnCalculateClick(e) =
    txtCommissionAmount.Text <- (sprintf "%0.02f" ((fun x y -> x * y / 100.00) (float txtWeeklySales.Text) (float txtCommissionRate.Text)))
   
   
 

Home Copyright © 2009-2015, FunctionX Home