Home

Functions

 

Functions Fundamentals

 

Introduction

A function is a section of code that performs an action and may produce a result.

Creating a Function

The fundamental formula used to create a function is:

let FunctionName = Function Body

You start with the let keyword, followed by a name for the function. The name of the function binds it to the value it would produce. The name follows the rules we saw for names in the F# language. Here is an example that starts a function:

let show . . .

Defining a Function

Defining or implementing a function consists of specifying its purpose, that is, what the function is supposed to accomplish. The definition or implementation of a function is done in its body, which is after the = sign. If the purpose of the function is short, the body can directly follow the = sign. Here is an example where the body of of the function simply uses printfn to display a sentence:

let show = printfn "Employee Record"

If the purpose of the function is long, it may need various lines of code. In this case, the body must start on a line after the = sign. In this case also, the body of the function must be indented. The indentation can be created by simply pressing the Space bar from the level of the let keyword used on the function. To make your code better to read, indentation is typically applied by using 2 or 4 spaces (some of us typically press the Tab key). The formula to create the function would be:

let FunctionName =
    Function Body

Here is an example:

let show =
    printfn "Employee Record"

Normally, you can do anything you want in the body of a function. For example, if necessary, you can declare one or more variables and use them as you see fit. The variables declared in a function are referred to as local variables. Here is an example of a local variable:

let show =
    let sentence = "We need to talk!"
    printfn "Sentence: %s" sentence

In the body of a function, if you use code that leads to dependent lines, as is typical in conditional statements, the dependent lines must be indented. Here is an example:

let show =
    let employeeName = "Leah Hanson";
    let employmentStatus = "Part-Time"
    let mutable salary = 12000.00;
    let experience = 5 // years
    
    if employmentStatus = "Part-Time" then
        salary <- 40000.00
    elif employmentStatus = "Full-Time" then
        if experience < 5 then
            salary <- 50000.00
        elif (experience >= 5) && (experience < 10) then
            salary <- 65000.00
        else // experience > 10 years
            salary <- 75000.00
    else // employmentStatus unknown
        salary <- 25000.00
    
    printfn "Employee Record"
    printfn "Full Name:  %s" employeeName
    printfn "Status:     %s" employmentStatus
    printfn "Experience: %d" experience
    printfn "Salary:     %.0f" salary

Calling a Function

After creating a function, to see its result, you must call it. If you create the functions as we have done so far, there is nothing to do: the function would be called automatically:

let show =
    let employeeName = "Leah Hanson";
    let employmentStatus = "Part-Time"
    let mutable salary = 12000.00;
    let experience = 5 // years
    
    if employmentStatus = "Part-Time" then
        salary <- 40000.00
    elif employmentStatus = "Full-Time" then
        if experience < 5 then
            salary <- 50000.00
        elif (experience >= 5) && (experience < 10) then
            salary <- 65000.00
        else // experience > 10 years
            salary <- 75000.00
    else // employmentStatus unknown
        salary <- 25000.00
    
    printfn "Employee Record"
    printfn "Full Name:  %s" employeeName
    printfn "Status:     %s" employmentStatus
    printfn "Experience: %d" experience
    printfn "Salary:     %.0f" salary

This would produce:

Employee Record
Full Name:  Leah Hanson
Status:     Part-Time
Experience: 5
Salary:     40000
Press any key to continue . . .

As an alternative, if you want to explicitly call a function, when creating it, add some empty parentheses. Then, to call the function, type its name. Here is an example:

let show() = printfn "Employee Record"

show

This would produce:

Press any key to continue . . .

If the function was created with empty parentheses, then you must follow its name with empty parantheses. Here is an example:

let show() = printfn "Employee Record"

show()

This would produce:

Employee Record
Press any key to continue . . .

Parameters and Arguments

 

Introduction

To perform its actions, a function may need external values. These are called parameters and they must be supplied to the function. The formula to create such a function is:

let FunctionName Parameters = Function Body

In this case, after the name of the function, create a list of parameters represented each by a name. If the function is using one parameter, simply type its name. Here is an example of a function named calculate and that takes one parameter:

let calculate x . . .

If the function is taking more than one parameter, separate them with spaces. Here is an example:

let calculate x y z . . .

The Data Type of a Parameter

You don't have to specify the data type of a parameter. If you don't, the compiler will have to figure out what type to apply to the parameter. To start, the computer would automatically infer that the parameter is an integer, of type int. In many cases, you should (must) specify the data type of a parameter. For example, if the parameter uses a value other than an integer, if a function is using more than parameter and at least one of them is not an integer type, it is better to indicate the data type of the parameter.

To specify the data type of a parameter, include the parameter in parentheses, type : followed by its data type. Here is an example:

let calculate (x:int) . . .

If the function takes more than one parameter and you want to specify the data type of each, include the combination of the variable name and its data type in parentheses. Here is an example:

let calculate (x:int) (y:int) (z:int) . . .

If the function is taking more than one parameter but one of them is an integer type, you can specify the data types of the other parameters and omit that of the integer type. Here is an example:

let showStudentInfo (name:string) age

As mentioned already, if you don't specify the data type of a parameter, the compiler first infers that the parameter is an integer type. In reality, when the function processes that parameter, the type of operation can indicate the actual type of the parameter.

To define or implement the function, after the parameter or the list of parameters and the assignment operator "=", in the body section, use the parameter(s) as you see fit. Here is an example that indicates that a function named show receives a string parameter and will display the value of that parameter using the printfn function:

let show message = printfn "%s" message;

Once again, remember that if a function is short enough, you can define it on the same line as the function name. If the function is long, start its body in the lines after = and indent the code. Here is an example:

let show message =
    printfn "%s" message;

Also remember that you can declare local variables in the function and use them as necessary. Here is an example:

let calculate (x:int) (y:int) (z:int) =
    let addition = x + y + y;
    printfn "%d + %d + %d = %d" 2 4 6 addition

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 is an example of a function named show that is created inside a function named calculate:

let calculate (x:int) (y:int) (z:int) =
    let addition = x + y + y;
    let show message =
        printfn "%s" message;
    printfn "%d + %d + %d = %d" 2 4 6 addition
    show "Welcome to the wonderful world of functional programming!";

calculate 2 4 6;

Calling a Function With Parameters

To call a function that takes arguments, you can just type its name. If you don't specify the value of the parameter, the call would produce an empty result. If you want to use the parameter that the function has, you must supply a value for the parameter. This is referred to as passing the argument to the function. To do this, after the name of the function, add a space and the argument or the list of arguments. Here is an example:

let show message = printfn "%s" message;

show "Welcome to the wonderful world of functional programming!";

This would produce:

Welcome to the wonderful world of functional programming!
Press any key to continue . . .

If the function is taking more than one argument, when calling it, type the name of the function followed by the value of each parameter. The values are separated by spaces. In the same way, if the function has a local variable, it is called the same way. Here is an example:

let calculate (x:int) (y:int) (z:int) =
    let addition = x + y + y;
    printfn "%d + %d + %d = %d" 2 4 6 addition;

calculate 2 4 6;

Automatic Generalization

Once again, 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.

Returning a Value From a Function

 

Introduction

When a function has performed its assignment, it may or may not produce a value. In some languages such as Visual Basic, Pascal, or Ada, a function that doesn't produce a value is called a procedure.

If a function produces a value, that function is said to return a value. In some languages such as Visual Basic or Pascal, a procedure that produces a value is called a function.

If you create a function and appropriately define it, the compiler will try to find out the type of value the function must return. Consider the following function:

let multiply(a) =
    a * 2

Obviously this function should always return a number (an integer). Now consider the following function:

getValue(value) = value

You can pass any type of value to this function and it would react appropriately. For example, you can pass a number:

let getValue(value) = value

getValue(28)

Or you can pass a string:

let getValue(value) = value

getValue("James Thoedore Leasy")

Obviously this function can return any type of value. 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

If the function will not return a known value, set its return type as unit. Here is an example:

let show() : unit =
    printfn "This is the house of the scorpion"

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 =
    printfn "Number 1: %d" x
    printfn "Number 2: %d" y
    printfn "Number 3: %d" z
    x + y + y;

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

Remember that if you use only the name of the function without passing some arguments, that is without specifying the values of the arguments, the function would produce an empty value.

Using the Returned Value of a Function

When calling a function, you can get its return value and use it as you see fit. For example you can display the value to the user. You can retrieve the value and store it in a variable. To do this, you can assign the function to a declared variable. Here is an example:

let calculate (x:int) (y:int) (z:int) = x + y + y;

let result = calculate 2 4 6;

printfn "%d + %d + %d = %d" 2 4 6 result;

By the way, because F# is an inferred language, you can create a function without specifying its return value. If you want to indicate the return type of the function, just before its assignment operator, type : followed by the data type. Here is an example:

let calculate (x:int) (y:int) (z:int) : int = x + y + y;

let result = calculate 2 4 6;

printfn "%d + %d + %d = %d" 2 4 6 result;

Instead of first declaring a variable to hold the returning value of a function, you can call the function directly where its value is needed. In the case of a placeholder of the printf or the printfn function, you must include the whole call in parentheses. Here is an example:

let multiply(a) = a * 2

printfn "Number: %i\n" (multiply(44));

This would produce:

Number: 88

Press any key to continue . . .

In a function that contains more than one expression, the return value of the function is the last expression it performs.

As mentioned already, if you don't specify the data type of a parameter, the compiler infers the type. Consider the following example:

let calculatePayrol salary time =
    salary * time

let result = calculatePayrol 20 38
printfn "Weekly Salary: %d" result;

If you are using Microsoft Visual Studio and if you position the mouse on a parameter, a tool tip would indicate the inferred data type of a parameter:

Parameter Data Type

We also metioned that the way the parameter is used in the body of the function can suggest its type. In the above cases, the compiler automatically infers that the parameters use integral numbers. The calling of a function can also suggest the type of a parameter. Consider the following example:

let calculatePayrol salary time =
    salary * time

let hourlySalary = 20.15;
let weeklyTime   = 38.50;
let result = calculatePayrol hourlySalary weeklyTime

printfn "Hourly Salary: %.02f" hourlySalary
printfn "Time Worked:   %.2f"  weeklyTime
printfn "Weekly Salary: %.02f" result;

Although the definition of the function has not changed, the compiler infers a float for it:

Parameter Data Type

Partially Passing Arguments

When you call a function that takes argument(s), you are supposed to pass the appropriate type(s) and the right number of arguments. F# allows you to pass a fewer number of arguments but... Consider the following example:

let add x y = x + y

let addition = add 36.94

Notice that, when it is defined, the add() function takes two parameters but when it is called, it is passed only one argument, and its call is assigned to a local variable named addition. If/when you do this, the compiler considers that you have just created a new function named addition and that takes one argument. When you call the function and pass a partial number of argumnets, it is as if you are telling the compiler that you plan to call the function but you don't yet have all the arguments; so you are temprarily first passing this (these) argument(s) and the other argument(s) will be passed at a later time. This means that, to get the actual value produced by the original function (in this case, add), you must call the variable as argument and pass the additional value(s) to it. Here is an example:

let add x y = x + y

let addition = add 36.94
let result = addition 48.27
printfn "Addition of 36.94 to 48.27: %0.02f" result

This would produce:

Addition of 36.94 to 48.27: 85.21
Press any key to continue . . .

You can apply the same technique regardless of the number of arguments. Here is an example:

let calculate a b c d = a + b * c - d

let firstCall = calculate 36.94 55.72
let secondCall = firstCall 9.96
let result = secondCall 29.07
printfn "55.72 * 9.96 + 36.94 - 29.07 = %0.04f" result

This would produce:

55.72 * 9.96 + 36.94 - 29.07 = 562.8412
Press any key to continue . . .

 

Ignoring the Return Value of a Function

We saw how to call a function and get the value it returns. Sometimes, when calling a function, you may not be interested in the value it return, only in the object of calling that function. When calling a function, to indicate that you are not interested in the value it is returning, at the end of the function call, type |> ignore. Here is an example:

let greet value = printfn value;

greet "Welcome to the wonderful world of functional programming!" |> ignore;
   
 

Topics on Functions

 

The Unit Type

All of the data types we have seen so far are used to represent known values. Variables or values of those types can be combined in/as expressions to produce new values. In the same way, a function can be created to return a value of one of those types. In some cases, you may not want a function to return a regular value, or a function may not return a known value, or the return value of a function is not clearly known. Such as function is said to return a void or a unit type. Actually, the void keyword is mostly used in C-based languages to represent the same thing.

The unit type is represented as an empty placeholder, represented as empty parentheses (). When you must use a unit type in a function, such as if passing an argument of unknown type, pass the type as unit. Here is an example:

let show(unit) = printfn "Employee Record"

In most cases, you can also pass the argument as an underscore. On the other hand, to indicate that a function doesn't return a value, specify its return type as unit. Here is an example:

let show() : unit = printfn "Employee Record"

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. Here another example:
    type Gender
    | Male
    | Female
    | Unknown
    
    createMemberSummary : string -> Gender -> float -> string
    This means that we have a function named createMemberSummary. The function takes three arguments. The first is a string. The second argument is based on the Gender enumeration. The third argument is a floating-point number. The function returns a string

The Entry Point of a Program

Many computer languages, especially compiled languages like C, C++, Visual Basic (the original BASIC language doesn't apply here), Java, and C# have a special function named main (or Main) that controls where a program starts executing. That function, or the section where it is defined, is called an entry point. Many other languages, especially interpreted languages (like JavaScript, VBScript, etc) don't have that function.

The F# language doesn't directly support the entry point concept. In fact, F# proceeds from the top of the document that contains the code (of a program) to the bottom section of the document. To specify an entry point for an F# program, somewhere in the document that holds the code of the application, create a section that starts with an attribute named EntryPoint. This would be done as follows:

[<EntryPoint>]
. . .

On the line(s) after the [<EntryPoint>] attribute, you can specify what to do. Here is an example:

[<EntryPoint>]
printfn "The buck starts here!";

This program will not do anything significant. The reason you create an entry poing is if you want to specify the starting point of execution of the program. To do this, you should a function named main and that takes one argument (the argument will actually be treated as a group of values, called an array). In the body of the function, do whatever you want. Before exiting the function, you should indicate a constant integer as its return value. Normally, you can use any number. Here is an example:

[<EntryPoint>]
let main arguments
    printfn "The buck starts here!"
    1250

By tradition, the return value of the entry point function is specified as 0.

Doing Something

The F# language provides the do keyword that can be used to perform an action without creating a function. The formula to use the do keyword is:

[ attributes ]
do expression

If you have some attribute(s) you want to use to control the execution of the section, start with that (those) attribute(s). If the expression is short enough, you can write do and the expression on the same line. Here is an example:

do printfn "Welcome to the wonderful world of F# programm!"

If the expression is long, type on its own line but indent it.  Here is an example:

do
    printfn "Welcome to the wonderful world of F# programm!"

Asserting an Expression

Consider the following program that provides a radius of a circle and calculates the diameter:

let radius = 25.08
let diameter = radius * 2.00

printfn "Circle Characteristics"
printfn "----------------------"
printfn "Radius:   %0.02f" radius
printfn "Diameter: %0.02f\n" diameter

This would produce:

Circle Characteristics
----------------------
Radius:   25.08
Diameter: 50.16

Press any key to continue . . .

Here is another version of the program with a negative value for the radius:

let radius = -25.08
let diameter = radius * 2.00

printfn "Circle Characteristics"
printfn "----------------------"
printfn "Radius:   %0.02f" radius
printfn "Diameter: %0.02f\n" diameter

The F# language provides a special function used to evaluate an expression. The function is named asset and its syntax is:

assert expression

The expression must evaluate to a True or False result. Here is an example:

let radius = -25.08
let diameter = radius * 2.00

assert (radius > 0.00)

printfn "Circle Characteristics"
printfn "----------------------"
printfn "Radius:   %0.02f" radius
printfn "Diameter: %0.02f\n" diameter

When the assert() function is called, if it returns false, the compiler displays an error dialog box and stops. The above program would produce:

Asserting an Expression

Of course, if the function returns true, the program proceeds normally.

Conditional Return

A function is meant to return a value, but that value may depend on some condition. For example, imagine you have a function that takes a value, must evaluate it, and returns either a simple value or an expression. In this case, you can create a conditional statement and return a value. Here is an example:

let getMembership c : string =
    if c = 1 then
        "Teen"
    elif c = 2 then
        "Adult"
    else
        "Senior"

let result = getMembership 2
printfn "Library Membership Category: %s" result;

This would produce:

Library Membership Category: Adult
Press any key to continue . . .

When you create a function that conditionally returns a value, make sure that function returns a value before its end. Otherwise you would receive an error (in reality, the error is more likely to occur in other languages like C/C++/C#, Java, or Visual Basic because those languages explicitily use a keyword to indicate the return value while in F#, any last expression in a function is considered as the return value).

Applying a Value to a Function

To apply a value to a function, use the <| operator. The formula to use is:

Function <| Value

The function appears on the left of the operator while the value is on the right. Here is an example:

let doubled a = 2 * a;
let result = doubled <| 46;

printfn "The double of 46 is %d" result;

This would produce:

The double of 46 is 92
Press any key to continue . . .

An alternative is to use the |> operator. In this case, the value must be written to the left of the operator and the function to the right.

Inline Functions

If you create function that uses a long body, which means its implementation spans various lines, and if you call that function many times, everytime the function is called, the compiler must "travel" from the section where the function is called to where it is defined. This travel can be done too many times, putting a big burden on the compiler. On the other hand, if the function is short, to cut this travel, you can ask the compiler to bring the definition of the function to where it is called. To do this, when defining the function, precede it with the inline keyboard. Here is an example:

let inline show message = printfn "%s" message;

show "Welcome to the wonderful world of functional programming!";

or:

let inline show (message:string) = printfn "%s" message;

show "Welcome to the wonderful world of functional programming!";

A Function as Parameter

By definition, a function is a value by itself. This means that one function can be directly defined in the body of another function. Such a function is passed as a parameter and it is called a function value.

To pass a function as parameter, after the name of the function that takes it as argument but before its own argument(s), open some parentheses. In the parentheses, enter a name for the function passed argument, followed by a column, the data type of its argument, followed by ->, and the data type(s) of its argument(s). Here is an example:

let display (show : string -> unit) message = show message;

This means that you are creating a function named display, that takes two parameters. One (the first) parameter is a function named show. This function takes an argument of type string and returns a unit (unknown) type. The second argument of the main function is named message. As done for every function, type = followed by the body of the function.

Before calling the main function, you must define the function, or you must define a function that performs the task of the function value. Here is an example:

let present msg = printfn "Welcome to the wonderful world of functional programming!";

When calling the main function, pass the necessary arguments. Here is an example:

let display (show : string -> unit) message = show message;
let present msg = printfn "Welcome to the wonderful world of functional programming!";

let d = display present "";

If the function value is taking more than one parameter, represent each as -> followed by its type.

let greetings msg = printfn "Welcome to the wonderful world of F#."

greetings (fun msg -> printfn msg) |> ignore;

In the section about lambda expresion, we used only one parameter. In reality, you can pass as many arguments as you want. Imagine you want to create a function that solves the equation ax + b = c. Such a function would take three arguments (a, b, and c), solve the equation, and return a new value. Here is an example:

let solve a b c = (c - b) / a;

You can then pass such a function as argument to another function. Here is an example:

let solve a b c = (c - b) / a;

let solveEquation pred x y z =
    printfn "In solving %dx + %dy = %dz, we get x = %d" x y z (pred x y z);

When calling the second function, you can include a call to the function that actually solves the problem. Here is an example:

let solve a b c = (c - b) / a;

let solveEquation pred x y z =
    printfn "In solving %dx + %dy = %dz, we get x = %d" x y z (pred x y z);

let res = solveEquation solve 1 -4 10

This would produce:

In solving 1x + -4y = 10z, we get x = 14
Press any key to continue . . .

The function would be better written to process each factor to make the final result display better. Here is an example:

let solve a b c = (c - b) / a;

let solveEquation pred a b c =
    printf "In solving "
    if a = -1 then
        printf "-x"
    elif a = 1 then
        printf "x"
    else
        printf "%dx" a;
    if b < -1 then
        printf "%d" b
    elif b = -1 then
        printf " - %d" (-1 * b)
    elif b = 0 then
        printf ""
    else // b > 0 then
        printf "+%d" b
    
    printf "=%d, " c
    
    printfn "we get x = %d\n" (pred a b c);

solveEquation solve 1 -4 10
solveEquation solve 2 -4 10
solveEquation solve 1 5 12
solveEquation solve 1 -3 5
solveEquation solve 7 0 21
solveEquation solve 8 -2 14

This would produce:

In solving x-4=10, we get x = 14

In solving 2x-4=10, we get x = 7

In solving x+5=12, we get x = 7

In solving x-3=5, we get x = 8

In solving 7x=21, we get x = 3

In solving 8x-2=14, we get x = 2

Press any key to continue . . .

Lambda Expressions

Imagine you have a relatively small function such as one that calculates the square of a number. Here is such a function:

let squareIt a = a * a

An anonymous function, also called a function expression, is a function that doesn't have a name. In reality, a lambda expression is a type of function that is passed to another function as argument, as we saw about function values. This time, to create the function you are passing as argument, that is, to create the lambda expression, use the following formula:

fun parameter(s) -> expression

This time, the expression starts with the fun keyword. This time also, the function is not named. Instead, the fun keyword is followed by the name(s) of the parameter(s) of the function/expression. After the name(s) of the parameter(s), type the -> operator and the purpose or definition of the function. Here is an example:

fun x -> x * x

You pass this whole definition to the function that receives it. Here is an example:

calculate (fun e -> e * e) 12

You must (have) define(d) a function that specifies what the parent function does. In that parent function, the lambda expression is represented by a name. That name is usually set as pred, which stands for predicate. Here is an example where a function takes one function as argument and another value as another argument. The parent function doubles the value of the parameter and passes the value to the lambda expression:

let calculate predicate number =
    let doubled = number * 2
    predicate doubled;

Remember that if you want, in some cases, you can retrieve the return value of the function and store it in a variable. Here is an example:

let calculate predicate number =
    let doubled = number * 2
    predicate doubled;

let result = calculate (fun e -> e * e) 12
printfn "Number = %d" result;

This would produce:

Number = 576
Press any key to continue . . .

In some cases, if you are not interested in the return value of the function, you can instruct the compiler to ignore it.

As seen previously, an alternative to passing a function as argument is to use a lambda expression. Here are examples from a function we saw previously:

let solveEquation pred a b c =
    printf "In solving "
    if a = -1 then
        printf "-x"
    elif a = 1 then
        printf "x"
    else
        printf "%dx" a;
    if b < -1 then
        printf "%d" b
    elif b = -1 then
        printf " - %d" (-1 * b)
    elif b = 0 then
        printf ""
    else // b > 0 then
        printf "+%d" b
    
    printf "=%d, " c
    
    printfn "we get x = %d" (pred a b c);

solveEquation (fun a b c -> (c - b) / a) 1 50 120
solveEquation (fun a b c -> (c - b) / a) 1 -5 7
solveEquation (fun a b c -> (c - b) / a) 4 0 8
solveEquation (fun a b c -> (c - b) / a) 1 -4 2
solveEquation (fun a b c -> (c - b) / a) 1 8 72
solveEquation (fun a b c -> (c - b) / a) 5 0 10

These would produce

In solving x+50=120, we get x = 70
In solving x-5=7, we get x = 12
In solving 4x=8, we get x = 2
In solving x-4=2, we get x = 6
In solving x+8=72, we get x = 64
In solving 5x=10, we get x = 2

Press any key to continue . . .

As mentioned earlier, the main idea to use a lambda expression is to let it handle a small assignment. The implementation of such a function can simply be assigned to a variable. Here is an example:

let multiply = fun a b -> a * b

In this case, notice that the variable is just that: it doesn't take any argument because it is not a function. On the other hand, you can use that variable where the function would have been called but pass the appropriate arguments. Here are two examples:

Author Note

Electric companies charge their customers on the amount of kilowatts they consume each month. In the following example, an electric company charges a base price of $8.50. Then, for the first 700 kWh, the company charges $0.0650/kWh, and $0.0500/kWh.

let compare = fun a b -> a <= b
let multiply = fun a b -> a * b

let calculateBill basePrice consumption =
    let mutable priceBasedOnConsumption = 0.00
    let priceForFirst700kWh = 0.0650 // per kWh
    let priceOver700kWh     = 0.0500 // per kWh

    if compare consumption 700.00 then
        priceBasedOnConsumption <- multiply consumption priceForFirst700kWh
    else
        priceBasedOnConsumption <- multiply consumption priceOver700kWh

    basePrice + priceBasedOnConsumption
    
let total = calculateBill 8.50 622.00

printfn "Electric Utility Company"
printfn "-------------------------"
printfn "Account #:  293-807-947"
printfn "Amount Due: %0.02f" total
printfn "========================="

This would produce:

Electric Utility Company
-------------------------
Account #:  293-807-947
Amount Due: 48.93
=========================
Press any key to continue . . .

Recursive Functions

A recursive function is a function that calls itself. Usually, the function performs an operation first, then calls itself to perform the operation again. Because this can be done over and over again, the function must define when and how to stop.

To create a recursive function, you use one of the following formulas:

let rec function-name parameter(s) = 
   function-body

or

let rec function1-name paramet(s) =
   function1-body
and function2-name parameter-list =
   function2-body
...

You start with the let rec expression followed by the name of the function and at least one parameter and =.  Based on the first formula, you can define the function in its body. Here is an example:

let rec AdditionalOdd a =
    if a <= 1 then
        1
    else
        a + AdditionalOdd(a - 2);

let number = 9;
let result =  AdditionalOdd number;

printfn "Sum of odd numbers from 1 to 9: %d" result;

This would produce:

Sum of odd numbers from 1 to 9: 25
Press any key to continue . . .

Composing Some 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 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" is to another simpler function to get the area of a sphere.

The F# language allows you to "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 begining, 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:

let PI = 3.14156;

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

printfn "Area of Sphere: %f\n" ((calculateCircleArea << multiplyBy4) 25.85)

You can also assign the result of that operation to a variable and then use that variable where necessary. 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 result = (calculateCircleArea << multiplyBy4) 25.85

printfn "Area of Sphere: %f\n" result

Another option is to assign the composition without the argument(s) to 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 multiplyBy4 value = 4.00 * value; // Area of a Sphere

let area = calculateCircleArea << multiplyBy4
let result = area 25.85

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
    printfn "Area of Sphere: %f\n" result
    This would produce:
    Area of Sphere: 33588.177234
    
    Press any key to continue . . .
  • 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";
    
    printfn "%s" g;

    This would produce:

Announcement: Welcome to the wonderful world of functional programming - F# is fun!
Press any key to continue . . .

Composing Many Functions

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

let hourlySalary = 25.85

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

printfn "Yearly Salary: %0.0f\n" yearlySalary

This would produce:

Yearly Salary: 49632

Press any key to continue . . .

Here is an example with five functions:

let hourlySalary = 25.85

// 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

printfn "Yearly Salary: %0.0f" yearlySalary

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

. . .           

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

let yearlySalary = yearEvaluation hourlySalary

printfn "Yearly Salary: %0.0f" yearlySalary

Composing Lambda Expressions

In the previous examples, we first defined the function to compose. As an alternative, you can create the function directly in the placeholder. This is done by creating a lambda expression. Here are examples:

let hourlySalary = 25.85          

let yearEvaluation = (fun salary -> salary * 8.00) >> (fun value -> value * 5.00) >> (fun value -> value * 2.00) >> (fun value -> value * 2.00) >> (fun value -> value * 12.00)

let yearlySalary = yearEvaluation hourlySalary

printfn "Yearly Salary: %0.0f" yearlySalary

Remember that, to make your code easy to read, you can write each function preceded by its << or >> on its own line with proper indentation. Here are examples:

let hourlySalary = 25.85          

let yearEvaluation =
       (fun salary -> salary * 8.00)
    >> (fun value  -> value  * 5.00)
    >> (fun value  -> value  * 2.00)
    >> (fun value  -> value  * 2.00)
    >> (fun value  -> value  * 12.00)
    
let yearlySalary = yearEvaluation hourlySalary

printfn "Yearly Salary: %0.0f" yearlySalary

Pipelining Some Functions

 

Introduction

Consider the previous example where we were calculating the area of a sphere from the area of a circle:

let PI = 3.14156;

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

Another way to chain functions is referred to as pipelining. It uses slightly different rules compared to composition. First, Instead of << or >>, pipelining uses the <| or the |> operator. Second, when performing the operation, pass the argument to the first function that will execute. As mentioned for pipelining:

  • If you use the |> operator, the function on the left side will execute first, and that's the function to which you must pass the argument(s). Here is an example:
    let PI = 3.14156;
    
    let calculateCircleArea radius = radius * radius * PI; // Area of a Circle
    let multiplyBy4 value = 4.00 * value; // Area of a Sphere
    
    // Passing the argument to the left side of the |> operator
    printfn "Area: %f" (calculateCircleArea 25.85 |> multiplyBy4)
    This would produce:
    Area of Sphere: 8397.044308
    
    Press any key to continue . . .
  • If you use the <| operator, the function on the right side of the operator will execute first. That's the function to which you must pass the argument(s).

You can pipeline as many functions as you want. You can perform the operation directly where needed. Here is an example that pipes two functions:

let greetings msg = msg + " - F# is fun!";
let define    msg = "Announcement: " + msg;

let g = "Welcome to the wonderful world of functional programming" |> define |> greetings;

printfn "%s" g;

Here is an example with many functions:

let hourlySalary = 25.85

let calculateDailySalary salary = salary * 8.00
let calculateWeeklySalary salary = salary * 8.00 * 5.00
let weeklySalary daily = daily * 5.00
let calculateBiMonthlySalary salary = salary * 8.00 * 5.00 * 2.00
let biMonthlySalary weekly = weekly * 2.00
let calculateMonthlySalary salary = salary * 8.00 * 5.00 * 2.00 * 2.00
let monthlySalary biMonthly = biMonthly * 2.00
let calculateYearlySalary salary = salary * 8.00 * 5.00 * 2.00 * 2.00 * 12.00
let yearlySalary monthly = monthly * 12.00

let yearlyEvaluation = calculateDailySalary hourlySalary |> weeklySalary |> biMonthlySalary |> monthlySalary |> yearlySalary

printfn "Yearly Salary: %0.0f" yearlyEvaluation

As mentioned for the composition, if the pipelining involves many functions and makes the line of code too long, to make it easy to read, you can write each function and its operator on its own line. Here is an example:

let yearlyEvaluation =
    calculateDailySalary hourlySalary
    |> weeklySalary
    |> biMonthlySalary
    |> monthlySalary
    |> yearlySalary

Instead of first creating the functions, you can define them directly where needed. In this case, you should create them as lambda expressions (we will see an example in the next section).

Chaining an Argument to Functions

On of the most valuable features of pipelining (and composing) is that you can pass (an) argument(s) once to a series of functions that can perform operations in chain, one after another. In this case, each function uses the return value of the previous function and applies that value to its own assignment. To do this, write the argument followed by a call to each function that is preceded by the necessary pipelining operator (<| or |>).

The formula to follow is:

argument(s) <| or |> function 1 <| or |> function 2 <| or |> function_n

Here is an example:

let hourlySalary = 25.85

let EvaluateDailySalary salary = salary * 8.00
let multiplBy5 value = value * 5.00
let multiplBy2 value = value * 2.00
let multiplBy12 value = value * 12.00

hourlySalary |> EvaluateDailySalary |> multiplBy5 |> multiplBy2 |> multiplBy2 |> multiplBy12 |> printfn "Yearly Salary: %0.02f"

To make the code easier to read, you should write a combination of the <| or the |> operator and the function on its own line. Here is an example:

hourlySalary
|> EvaluateDailySalary
|> multiplBy5
|> multiplBy2
|> multiplBy2
|> multiplBy12
|> printfn "Yearly Salary: %0.02f"

This makes it easy to know what function is called and in what order. Instead of first defining the functions, you can create each directly in its pipelining placeholder. Each function can be defined as a lambda expression. Here are examples:

let hourly = 25.85
let salary = 34.50

hourly |> fun value -> value * 8.00 |> fun value -> value * 5.00 |> fun value -> value * 2.00 |> fun value -> value * 2.00 |> fun value -> value * 12.00 |> printfn "Yearly Salary: %0.02f"

salary 
|> fun value -> value * 8.00
|> fun value -> value * 5.00
|> fun value -> value * 2.00
|> fun value -> value * 2.00
|> fun value -> value * 12.00
|> printfn "Yearly Salary: %0.0f"

This would produce:

Yearly Salary: 49632

Yearly Salary: 66240

Built-In Functions

   

Conversion Functions

F# provides various functions used to convert one value into another.

To convert a number to a character, call the char() function. Here is an example:

let number = 68;
let result = char number;

printfn "The character represnting 68 is %c" result;

This would produce:

The character represnting 68 is D
Press any key to continue . . .

To convert any value to a string, call a function named string. Here is an example:

let number = 138;
let result = string number;

printfn "Result: %s" result;

To convert a number to byte, call the byte() function. Here is an example:

let number = -85248;
let result = byte number;

printfn "The byte equivalent of -85248 is %d" result;

This would produce:

The byte equivalent of -85248 is 0
Press any key to continue . . .

To convert a number to a signed byte, call the sbyte() function.

To convert a value to an integer, use a function named int. Here is an example:

let result = int 628.305;

printfn "The decimal 628.305 converted to an integer is %d" result;

This would produce:

The decimal 628.305 converted to an integer is 628
Press any key to continue . . .

An alternative it to call a function named int32. To convert a number to an unsigned integer, call the uint32() function.

To convert a value to a short integer, call the int16() function. To convert a value to an unsigned short integer, call the unt16() function.

If you want to convert a number to a long integer, use the int64() function. To convert a number to an unsigned long integer, call the uint64() function.

To convert a value to native integer, call the nativeint() function. To convert the number an unsigned native integer, call the unativeint() function.

To convert a number to decimal, call the decimal() function. Here is an example:

let result = decimal 513;

printfn "The number 513 converted to decimal is %.3f" result;

This would produce:

The number 513 converted to decimal is 513.000
Press any key to continue . . .

To convert a value to a 32-bit decimal number, call the float32() function. To convert a value to a 64-bit decimal number, call the float() function.

Algebraic Functions

The F# language provides a series of functions you can use in your programs.

The numbers in your program can be positive or negative. A negative number is preceded by a - sign. To find the cign of a number, call a function named sign. This function takes one argument and works as follows:

  • If the value of the argument is positive, the function returns 1. Here is an example:
    let number = 8142;
    let rounder  = sign number;
    
    printfn "The sign of 8142 is %d" rounder;
    This would produce:
    The sign of 8142 is 1
    Press any key to continue . . .
  • If the value of the argument is negative, the function returns -1
  • If the value of the argument is 0, the function returns 0

To find the absolute value of a number or a variable, use the abs() function. Here is an example:

let solveEquation pred a b c =
    printf "In solving "
    match a with
    | -1 -> printf "-x"
    |  1 -> printf "x"
    | _  -> printf "%dx" a;
    if b <= -1 then
        printf " - %d" (abs b)
    elif b = 0 then
        printf ""
    else // b > 0 then
        printf " + %d" b
    
    printf " = %d, " c
    
    printfn "we get x = %d\n" (pred a b c);

solveEquation (fun a b c -> (c - b) / a) 1  2 -3
solveEquation (fun a b c -> (c - b) / a) 2 -1  2
solveEquation (fun a b c -> (c - b) / a) 1 10 15
solveEquation (fun a b c -> (c - b) / a) 2  0  8

This would produce:

In solving x + 2 = -3, we get x = -5

In solving 2x - 1 = 2, we get x = 1

In solving x + 10 = 15, we get x = 5

In solving 2x = 8, we get x = 4

Press any key to continue . . .

The compare() function is used to compare two numeric values. The function takes two arguments and behaves as follows:

  • If the value of the first (left) argument is lower than the value of the second (right) argument, the function returns -1. Here is an example:
    let result = compare 3 7;
    
    printfn "Comparing 3 and 7 produces %A" result;
    This would produce:
    Comparing 3 and 7 produces -1
    Press any key to continue . . .
  • If the value of the first (left) argument is equal to the value of the second (right) argument, the function returns 0. Here is an example:
    let result = compare 28 28;
    
    printfn "Comparing 28 and 28 produces %A" result;
    This would produce:
    Comparing 28 and 28 produces 0
    Press any key to continue . . .
  • If the value of the first (left) argument is higher than that of the second (right) argument, the function returns 1. Here is an example:
    let result = compare 7 3;
    
    printfn "Comparing 7 and 3 produces %A" result;
    This would produce:
    Comparing 7 and 3 produces 1
    Press any key to continue . . .

To calculate the natural logarithm of a floating-point number, call a function named log. Here is an example of calling it:

let number = 8.00;

printfn "The natural logarithm is %.3f" (log number);

This would produce:

The natural logarithm is 2.079
Press any key to continue . . .

To calculate the logarithm to base 10 of a decimal number, call the log10() function.

Floating-Point Functions

To round a number, call a function named round. Here is an example of calling this function:

let number = 8.142;
let rounder  = round number;

printfn "Rounding 8.142 produces %.0f" rounder;

This would produce:

Rounding 8.142 produces 8
Press any key to continue . . .

To truncate a number, call a function named truncate. Here is an example:

let nbr = 138.246;
let res = truncate nbr;

printfn "Result: %.3f" res;

This would produce:

Result: 138.000
Press any key to continue . . .

To find the ceiling of a number, call the ceil() function. To get the floor of a number, call the floor() function.

To calculat the power of a number raised to a power, use a function named pown. This function takes two arguments. Here is an example of calling it:

let number = 8.12;
let result  = pown number 4;

printfn "8.12 raised to the power of 4 is %.3f" result;

This would produce:

8.12 raised to the power of 4 is 4347.345
Press any key to continue . . .

To calculate the exponential of a function, call a function named exp. Here is an example:

let exponential = exp 12.24;

printfn "The exponential of 12.24 is %.3F" exponential;

This would produce:

The exponential of 12.24 is 206901.890
Press any key to continue . . .

To calculate the square root of a number, call the sqrt() function.

Trigonometric Functions

If you have a decimal number and you want to find its sine, the F# language provides a function named sin. Here is an example of calling it:

let result = sin 228.82;

printfn "The sine of 128 is %.3f" result;

This would produce:

The sine of 128 is 0.494
Press any key to continue . . .

To get the inverse sine of a function, call the asin() function. If you want to calculate the hyperbolic sine of a number, call the sinh() function.

To let you calculate the cosine of a decimal number, the F# language is equipped with a function named cos.

To get the inverse cosine of a number, call the acos() function. To get the hyperbolic cosine of a decimal number, use the cosh() function.

To calculate the tangent of a number, call a function named tan. To get the arctangent of a number, call the atan() function. To find the hyperbolic tangent of a number, call the tanh() function.

On the other hand, if you have a fraction represented as x / y, to get its inverse tangent, call the atan2() function. This function takes two arguments as the denominator followed by the numerator.

 
 
   
 

Previous Copyright © 2009-2015 FunctionX Next