Introduction to Functions
Introduction to 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 function-name = 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. Other than that:
Here is an example that starts a function:
let show . . .
After the name of the function, add the assignment operator.
Defining a Function
Defining or implementing a function consists of specifying its purpose, that is, what the function is supposed to accomplish.
The Body of a Function
The definition or implementation of a function is done in its body. The body of a function starts 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 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. A better solution is to press the Tab key. The formula to create the function would be:
let function-name =
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 above function would produce:
Employee Record Full Name: Leah Hanson Status: Part-Time Experience: 5 Salary: 40000 Press any key to close this window . . .
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 close this window . . .
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 close this window . . .
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 function-name 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 figure out what type to apply to the parameter. To start, the compiler 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 one 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. In those parentheses, after the name of the parameter, 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 parameter name and its data type in parentheses. Here are examples:
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
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 close this window . . .
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. 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;
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;
Creating a function in the body of another is alaos referred to as nesting a function.
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 action, 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")
The Return Type of a Function
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"
Returning a Constrant Value
In some computer languages (such as C-based languages (C++, Java, C#) and others (such as Visual Basic), to indicate when a function returns a value, you must use a special word, such as return (in C++, Java, C#, or Return in Visual Basic). In F#, to indicate the value that a function returns, you can simply type that value as only thing in the function. Here is an example:
let generalize() = 22_500
Of course, the above could also have been written on its own line:
let generalize() =
22_500
The return value of a function can also be held by a variable. In this case, to indicate the variable that a function returns, simply type the name of the variable before the end line of the function. Here is an example:
let unitPrice = 149.95
let generalize() =
unitPrice
If a function contains more than one line of code, to indicate the value or variable that the function returns, type that value or the name of the variable as the las thing in the body of the function. Here are examples:
let calculate() =
let discountRate = 20.00
printf "Enter the price of the shirt: "
let unitPrice = float(stdin.ReadLine())
let markedPrice = unitPrice * discountRate / 100.00
markedPrice
Returning an Expression
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. Therefore, to indicate that the function returns an expression, type it in the body of the function. Here is an example:
let calculate x y z = x + y + y
Of course, the above expression could have been written on its own line to indicate that the function returns an expression. Here is an example:
let calculate x y z = x + y + y
In most cases, before its last line, the body of a function may contain multiple statements. In that case, to indicate that the function returns an expression, simply type that expression as the last line of the function. 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
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 close this window . . .
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:
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:
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 close this window . . .
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 close this window . . .
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 returns, 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
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 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:
presentGreetings : unit -> return-type
presentGreetings : parameter-type(s) -> unit
calculateCylinderVolume : float -> float -> floatThis 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 -> unitThis 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 is 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 stringThe 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.
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!"
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 close this window . . .
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 assert 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:
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 return 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 close this window . . .
When you create a function that conditionally returns a value, make sure that function returns a value before its end.
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 close this window . . .
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.
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 computer processor (and 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 as 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, or you must have defined, the function passed as argument. 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 same way, 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 close this window . . .
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 close this window . . .
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 close this window . . .
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 close this window . . .
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:
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 close this window . . .
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 close this window . . .
Functions Composition
Introduction
Imagine you have two or more functions in a program. Imagine the functions take the same number and type(s) of argument(s) and the operation(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. 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.
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
One of the operators to perform function compostion is << 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
The other operator to perform function comparison is >>. As a reasult, when composing two functions, you place one function to the left of << or >> and one function to the right of << or >>:
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 close this window . . .
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 close this window . . .
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 close this window . . .
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.
To perform pipelining, one of the operators you can use is <| (read "Left Pipelining"). To proceed, write the name of one function to the left of the operator and the name of the other function to the right of 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). 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 right side of the <| operator
printfn "Area: %f" (multiplyBy4 <| calculateCircleArea 25.85)
This would produce:
Area of Sphere: 8397.044308 Press any key to close this window . . .
Another operator used in pipelining is the |> operator (read "Right Pipelining"). Once again, write the name of one function to the left of the operator and the name of the other function to the right of the operator. This time, the function on the left side will execute first, and that's the function to which you must pass the argument(s). This means that you must pass the argument(s) between the function on the left of and the|> operator. 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)
Multi-Pipelining
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.
Chaining Arguments to Functions
Introduction
One 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. This is referred to as chaining functions. When chaining, each function uses the return value of the previous function and applies that value to its own operation.
Chaining Argument
To chain arguments, 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
F# provides various functions used to convert one value into another.
Conversion to a Character
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 close this window . . .
Conversion to a String
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 close this window . . .
Conversion to a Signed Byte
To convert a number to a signed byte, call the sbyte() function.
Conversion to an Integer
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 close this window . . .
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.
Conversion to a Decimal Number
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 close this window . . .
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
Introduction
The F# language provides a series of functions you can use in your programs.
The Sign of a Number
The numbers in your program can be positive or negative. A negative number is preceded by a - sign. To find the sign of a number, call a function named sign. This function takes one argument and works as follows:
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 close this window . . .
The Abolute Value of a Number
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 close this window . . .
Comparing Two Numbers
The compare() function is used to compare two numeric values. The function takes two arguments and behaves as follows:
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 close this window . . .
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 close this window . . .
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 close this window . . .
Getting the Natural Logarithm of a Number
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 close this window . . .
To calculate the logarithm to base 10 of a decimal number, call the log10() function.
Rounding a Number
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 close this window . . .
Truncating a Number
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 close this window . . .
The Ceiling of a Number
To find the ceiling of a number, call the ceil() function. To get the floor of a number, call the floor() function.
The Power of a Number
To calculate 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 close this window . . .
The Exponential of a Number
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 close this window . . .
To calculate the square root of a number, call the sqrt() function.
Trigonometric Functions
The Sine of a Number
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 close this window . . .
The Inverse Sine of a Number
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.
The Cosine of a Number
To let you calculate the cosine of a decimal number, the F# language is equipped with a function named cos.
The Inverse Cosine of a Number
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.
The Tangent of a Number
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.
The Inverse Tangent of a Number
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-2024, FunctionX | Thursday 16 February 2023 | Next |
|