Introduction to Delegates
Introduction to Delegates
Fundamentals of Delegates
Introduction
A delegate is an object that is created to act as, or in place of, a function. The delegate is primarily created as a type but with the signature of a function. This means that the function or object is not defined. It is only meant to represent a function that can be eventually called. Then, when necessary, the object as function would be called as a function.
The primary formula to create a delegate is:
type delegate-name = delegate of parameter-type -> return-type
You start with the required and common type keyword used to create types in F#. This is followed by a name for the delegate, which follows the rules for names of classes.
Besides the type keyword, the delegate name is followed by the = delegate of expression, which is required. If the function will not take a parameter, specify its parameter-type as unit. To complete the signature, you must add -> and tne return type of the function. If the function will not return a specific value, specify its return-type as unit. Here is an example:
type TitleCreation = delegate of unit -> unit
The F# language supports delegates through an abstract class named FSharpFunc:
[<AbstractClass>] type FSharpFunc<'T,'U> = class new FSharpFunc : unit -> FSharpFunc<'T,'U> static member FromConverter : Converter<'T,'U> -> 'T -> 'U abstract this.Invoke : 'T -> 'U static member InvokeFast : FSharpFunc<'T,('U -> 'V)> * 'T * 'U -> 'V static member InvokeFast : FSharpFunc<'T,('U -> 'V -> 'W)> * 'T * 'U * 'V -> 'W static member InvokeFast : FSharpFunc<'T,('U -> 'V -> 'W -> 'X)> * 'T * 'U * 'V * 'W -> 'X static member InvokeFast : FSharpFunc<'T,('U -> 'V -> 'W -> 'X -> 'Y)> * 'T * 'U * 'V * 'W * 'X -> 'Y static member ToConverter : ('T -> 'U) -> Converter<'T,'U> static member op_Implicit : Converter<'T,'U> -> 'T -> 'U static member op_Implicit : ('T -> 'U) -> Converter<'T,'U> end
The class is defined in the Microsoft.FSharp.Core namespace (https://github.com/dotnet/fsharp/blob/main/src/FSharp.Core/prim-types.fs) of the FSharp.Core.dll library. This means that you will hardly, if ever, need to use it in your programs. Instead, when you create a delegate, it directly becomes a class that is derived from FSharpFunc. This means that the members of the FSharpFunc class become direct members of your delegate.
When you create a delegate, it becomes an object (or a function object) of type FSharpFunc. The FSharpFunc class has a constructor and methods.
Associating a Function to a Delegate
As mentioned already, a delegate only represents the signature of a function. To use a delegate, you must associate it to a function. If you don't have one already, you can start by creating a function. Here is an example of a function:
let getTitle() : unit = printfn "Introduction to F# Programming, Second Edition"
As mentioned above, a delegate is an object of the FSharpFunc type. This class has a constructor. To associate a function to a delegate, declare a variable and initialize it with the constructor. Based on this, the primary formula to associate a function to a delegate is:
let variable-name = new delegate-name(function-name)
This is equivalent to declaring a variable for a type, as done for a class, using the name as constructor. In the parentheses of the contructor, type the name of the function as parameter. This can be done as follows:
type TitleCreation = delegate of unit -> unit
let getTitle() : unit =
printfn "Introduction to F# Programming, Second Edition"
let title = TitleCreation(getTitle)
You can optionally use the new operator when initializing the variable. Here is an example:
type TitleCreation = delegate of unit -> unit
let getTitle() : unit =
printfn "Introduction to F# Programming, Second Edition"
let title = new TitleCreation(getTitle)
The Type of a Delegate
Remember that, when declaring a variable, you can indicate the type of the variable. To do this when associating a function to a delegate, the formula to follow is:
let variable-name : delegate-name = new delegate-name(function-name)
Here is an example of specifying the type of the variable:
type TitleCreation = delegate of unit -> unit
let getTitle() : unit =
printfn "Introduction to F# Programming, Second Edition"
let title : TitleCreation = new TitleCreation(getTitle)
Invoking a Delegate
After associating the function to the delegate, you can use the variable as if it were a function. To let you do this, the FSharpFunc class that each delegate derives from, is equipped with a method named Invoke. All you have to do is to call this method to the delegate variable. Here is an example:
type TitleCreation = delegate of unit -> unit
let getTitle() : unit =
printfn "Introduction to F# Programming, Second Edition"
let title : TitleCreation = new TitleCreation(getTitle)
title.Invoke()
This would produce:
Introduction to F# Programming, Second Edition Press any key to close this window . . .
A Delegate that Returns a Value
A delegate presents the syntax of a function. As such, it can indicate whether its function(s) must return a value. That's the role of the last part of the formula we saw:
type delegate-name = delegate of parameter(s) type(s) -> return-type
Here is an example of a delegate that takes no parameter and returns a string:
type Initialyze = delegate of unit -> string
Remember that any function that will be associated with such a delegate must return the same type of value of that delegate. Here is an example:
type Initialyze = delegate of unit -> string
let initialyzer() = "Enterprise Database Design"
You associate the function to the delegate the same way we have done so far. Here is an example:
type Initialyze = delegate of unit -> string
let initialyzer() = "Enterprise Database Design"
let result = new Initialyze(initialyzer)
If you have a delegate that returns a value, when calling its function, you can use the value however you judge necessary, as long as you keep in mind the type of value the function is returning. Here is an example:
type Initialyze = delegate of unit -> string
let initialyzer() = "Enterprise Database Design"
let result = Initialyze(initialyzer)
printfn "Course Title: %s" (result.Invoke())
This would produce:
Course Title: Enterprise Database Design Press any key to close this window . . .
In the same way, you can use a delegate that takes one or more arguments and returns a value.
Delegates and Parameters
Introduction to Passing an Argument to a Delegate
As a delegate simply presents the layout of a function, it can use a parameter. Remember that the basic formula to create a delegate is:
type delegate-name = delegate of parameter-type -> return-type
In this case, in the signature of the delegate, only specify the data type of the parameter. Here is an example of a delegate that takes a string as parameter and returns no value:
type CourseDescription = delegate of string -> unit
Any function that will use this delegate must take the same type of parameter. Here is an example:
let describe str = printfn "Course Name: %s" str
To associate the function to the delegate, you declare a let variable as we have done so far. Initialyze it using the constructor of the delegate. Here is an example:
type CourseDescription = delegate of string -> unit
let describe str =
printfn "Course Name: %s" str
let desc = new CourseDescription(describe)
To support parameters, the FSharpFunc class provides many options on its Invoke() method. This includes the ability to pass one or more parameters. As a result, when calling Invoke, pass an argument that is the same type that was specified when creating the delegate and when defining the function. Here is an example:
type CourseDescription = delegate of string -> unit
let describe str =
printfn "Course Name: %s" str
let desc = CourseDescription(describe)
desc.Invoke("Enterprise Database Design")
You can omit the parentheses on the Invoke():
type CourseDescription = delegate of string -> unit
let describe str =
printfn "Course Name: %s" str
let desc = new CourseDescription(describe)
desc.Invoke "Enterprise Database Design"
This would produce:
Course Name: Enterprise Database Design Press any key to close this window . . .
A Delegate With Many Parameters
To indicate what its prototyped function(s) would look like, a delegate can take as many parameters as necessary. The formula to create such a delegate is:
type delegate-name = delegate of type_1 * type_2 * ... * type_n -> return-type
In the placeholder of the parameter, specify each type and separate them with *. Here is an example of a delegate for (a) function(s) that take(s) a string followed by an integer and returns a string:
type Initialyze = delegate of string * int -> string
Of course, when defining the function(s), make sure you use the same number of parameters and return the same type of value. Here is an example:
let initialyzer courseName credits = courseName + ", " + (string credits) + " credits"
To associate the function to the delegate, you proceed as we have done so far. Here is an example:
type Initialyze = delegate of string * int -> string let initialyzer courseName credits = courseName + ", " + (string credits) + " credits" let result = new Initialyze(initialyzer)
To let you use the variable, remember that the FSharpFunc.Invoke() method allows you to pass as many arguments as you need. Make sure you pass the same number of arguments and types specified in both the delegate and the function. Here is an example:
type Initialyze = delegate of string * int -> string
let initialyzer courseName credits =
courseName + ", " + (string credits) + " credits"
let result = Initialyze(initialyzer)
let value = result.Invoke("Enterprise Database Design", 3)
printfn "Course Title: %s" value
This would produce:
Course Title: Enterprise Database Design, 3 credits Press any key to close this window . . .
In the above example, we first declared a variable to store the value of calling the Invoke() method. This is not always necessary. Instead, you can call the method directly where it is needed. Here is an example:
type Initialyze = delegate of string * int -> string
let initialyzer courseName credits =
courseName + ", " + (string credits) + " credits"
let result = Initialyze(initialyzer)
printfn "Course Title: %s" (result.Invoke("Enterprise Database Design", 3))
A Delegate as a Parameter
Since a delegate is a type (like a class or a data type), it can be passed as argument to another delegate or to a function. To specify that a parameter is a delegate type, when creating the delegate, apply the name of a delegate. Of course, you must have a delegate. You can first create one and then use it. Here is an example of a delegate named Catalogue that takes a parameter that is of a type of delegate:
type Initialyzer = delegate of string * int -> string // First Delegate
type Catalogue = delegate of Initialyzer -> unit // Second Delegate
In the same way, you can pass a combination of (a) delegate(s) and other types of parameters passed to a delegate. Here is an example of a delegate that takes a delegate, two strings, and an integer as parameters. The delegate returns a string:
type Cataloguer = delegate of Initialyzer * string * string * int -> string
When creating the function(s), pass the same number and types of arguments. Make sure you pass the first delegate in the same placeholder. In the body of the function, declare a variable and initialyze it with a function that implements the first delegate. You have two options. If you will need the first function only inside the new function, and because the F# language allows it, you can define the first function inside the new function. Here is an example:
type Initialyzer = delegate of string * int -> string type Cataloguer = delegate of Initialyzer * string * string * int -> string let createCatalog (init : Initialyzer) name title credits = let initialyze courseName credits = courseName + "(" + (string credits) + ")" let course = new Initialyzer(initialyze)
Otherwise, if you will use the first function globally, you should define it outside the new function. Somewhere in the function, you can call the Invoke() method to get the value of the variable. Before exiting the function, if necessary, make sure you return the appropriate value indicated by both the delegate and the function. Here is an example:
type Initialyzer = delegate of string * int -> string
type Cataloguer = delegate of Initialyzer * string * string * int -> string
let createCatalog (init : Initialyzer) name title credits =
let initialyze courseName credits =
courseName + "(" + (string credits) + ")"
let course = new Initialyzer(initialyze)
name + ": " + course.Invoke(title, credits)
When calling the Invoke() method on the function variable associated with the second delegate, make sure you pass an argument in the appropriate placeholder of the delegate parameter. Here is an example:
type Initialyzer = delegate of string * int -> string
type Cataloguer = delegate of Initialyzer * string * string * int -> string
let initialyze courseName credits =
courseName + "(" + (string credits) + ")"
let createCatalog (init : Initialyzer) name title credits =
let course = Initialyzer(initialyze)
name + ": " + course.Invoke(title, credits)
let catalogue = Cataloguer(createCatalog)
let init = Initialyzer(initialyze)
let result = catalogue.Invoke(init, "CMIS 226", "Enterprise Database Design", 3)
printfn "Course Decription: %s" result
This would produce:
Course Decription: CMIS 226: Enterprise Database Design(3) Press any key to close this window . . .
Remember that if you are not planing to use the delegate value many times, you don't have to first declare a variable for it. You can write this:
type Initialyzer = delegate of string * int -> string type Cataloguer = delegate of Initialyzer * string * string * int -> string let initialyze courseName credits = courseName + "(" + (string credits) + ")" let createCatalog (init : Initialyzer) name title credits = name + ": " + (new Initialyzer(initialyze)).Invoke(title, credits) let catalogue = new Cataloguer(createCatalog) let result = catalogue.Invoke(new Initialyzer(initialyze), "CMIS 226", "Enterprise Database Design", 3) printfn "Course Decription: %s" result
Or this:
type Initialyzer = delegate of string * int -> string
type Cataloguer = delegate of Initialyzer * string * string * int -> string
let initialyze courseName credits =
courseName + "(" + (string credits) + ")"
let createCatalog (init : Initialyzer) name title credits =
name + ": " + (new Initialyzer(initialyze)).Invoke(title, credits)
let result = (new Cataloguer(createCatalog)).Invoke(new Initialyzer(initialyze), "CMIS 226", "Enterprise Database Design", 3)
printfn "Course Decription: %s" result
Or even this:
type Initialyzer = delegate of string * int -> string
type Cataloguer = delegate of Initialyzer * string * string * int -> string
let initialyze courseName credits =
courseName + "(" + (string credits) + ")"
let createCatalog (init : Initialyzer) name title credits =
name + ": " + (new Initialyzer(initialyze)).Invoke(title, credits)
printfn "Course Decription: %s" ((new Cataloguer(createCatalog)).Invoke(new Initialyzer(initialyze), "CMIS 226", "Enterprise Database Design", 3))
Delegates and Classes
Delegates and Methods
When you create a delegate, you don't specify that only functions can associate to it. A method can as well be associated to a delegate. The main difference is that you may have to create an object (declare a variable of a class) from which you would call the method. Of course, any method can be used as long as there is an appropriate delegate to which it can be associated. Other than that, everything else follows the rules we reviewed for functions:
type Creation = delegate of unit -> unit type EmploymentStatus = | Unknown = 0 | FullTime = 1 | PartTime = 2 | Intern = 3 | Seasonal = 4 type Employee(emplNbr, fname, lname, status, salary) = member val EmployeeNumber = emplNbr with get, set member val FirstName = fname with get, set member val LastName = lname with get, set member val Status = status with get, set member val HourlySalary = salary with get, set member this.Present() : unit = printfn "Employee Payroll Summary" printfn "----------------------------------------------------" printfn "Employee #: %s" this.EmployeeNumber printfn "Full Name: %s %s" this.FirstName this.LastName printfn "Status: %A" this.Status printfn "Hourly Salary: %0.02F" this.HourlySalary printfn "----------------------------------------------------" let empl = Employee("7092-3094", "Rose", "Crittenden", EmploymentStatus.FullTime, 24.05) let resume = Creation(empl.Present) resume.Invoke()This would produce:
Employee Payroll Summary ---------------------------------------------------- Employee #: 7092-3094 Full Name: Rose Crittenden Status: FullTime Hourly Salary: 24.05 ---------------------------------------------------- Press any key to close this window . . .
type Creation = delegate of unit -> unit type Calculation = delegate of bool * float -> float type EmploymentStatus = | Unknown = 0 | FullTime = 1 | PartTime = 2 | Intern = 3 | Seasonal = 4 type Employee(emplNbr, fname, lname, status, salary) = member val EmployeeNumber = emplNbr with get, set member val FirstName = fname with get, set member val LastName = lname with get, set member val Status = status with get, set member val HourlySalary = salary with get, set member this.CalculateSalary salaryIsFixed timeWorked = if salaryIsFixed = true then salary * 40.00 else salary * timeWorked let empl = Employee("7092-3094", "Rose", "Crittenden", EmploymentStatus.FullTime, 24.05) let result = Calculation(empl.CalculateSalary) printfn "Employee Payroll Summary" printfn "----------------------------------------------------" printfn "Employee #: %s" empl.EmployeeNumber printfn "Full Name: %s %s" empl.FirstName empl.LastName printfn "Status: %A" empl.Status printfn "Hourly Salary: %0.02F" empl.HourlySalary printfn "----------------------------------------------------" printfn "Weekly Salary: %0.02F" (result.Invoke(false, 44.50))This would produce:
Employee Payroll Summary ---------------------------------------------------- Employee #: 7092-3094 Full Name: Rose Crittenden Status: FullTime Hourly Salary: 24.05 ---------------------------------------------------- Weekly Salary: 1070.23 Press any key to close this window . . .
Delegates and Static Members of a Class
So far, we were declaring a variable to use a class outside its body. If you create a static method in a class and you want to associate that method to a delegate, remember that you don't have to declare an instance of the class to access that method. Here is an example:
type Calculation = delegate of bool * float -> float type EmploymentStatus = | Unknown = 0 | FullTime = 1 | PartTime = 2 | Intern = 3 | Seasonal = 4 type Employee() = static let mutable emplNbr = "" static let mutable fn = "" static let mutable ln = "" static let mutable status = EmploymentStatus.Unknown static let mutable sal = 0.00 static member EmployeeNumber with get() = emplNbr and set(value) = emplNbr <- value static member FirstName with get() = fn and set(value) = fn <- value static member LastName with get() = ln and set(value) = ln <- value static member Status with get() = status and set(value) = status <- value static member HourlySalary with get() = sal and set(value) = sal <- value static member CalculateSalary salaryIsFixed timeWorked = if salaryIsFixed = true then Employee.HourlySalary * 40.00 else Employee.HourlySalary * timeWorked Employee.EmployeeNumber <- "8485-2082" Employee.FirstName <- "Joseph" Employee.LastName <- "Almunia" Employee.Status <- EmploymentStatus.FullTime Employee.HourlySalary <- 32.25 let result = Calculation(Employee.CalculateSalary) printfn "Employee Payroll Summary" printfn "----------------------------------------------------" printfn "Employee #: %s" Employee.EmployeeNumber printfn "Full Name: %s %s" Employee.FirstName Employee.LastName printfn "Status: %A" Employee.Status printfn "Hourly Salary: %0.02F" Employee.HourlySalary printfn "----------------------------------------------------" printfn "Weekly Salary: %0.02F" (result.Invoke(true, 48.00))
This would produce:
Employee Payroll Summary ---------------------------------------------------- Employee #: 8485-2082 Full Name: Joseph Almunia Status: FullTime Hourly Salary: 32.25 ---------------------------------------------------- Weekly Salary: 1290.00 Press any key to close this window . . .
An Object as a Parameter to a Delegate
As we saw already, a delegate can take a parameter and/or return a value. The parameter of a delegate can be a primitive type or a class. Here is an example:
type Description = delegate of BasketballCourt -> unit
This an example of a delegate for a function that would take a parameter from a class named BasketballCourt. Of course, you must use a type of object. You can use an existing class or you can create your own. When defining the function, you must pass an object of the same type passed to the delegate. The rest is done as we saw so far. Here is an example:
type Rectangle() = let mutable len = 0.00 let mutable wd = 0.00 member this.Length with get() = len and set(value) = len <- value member this.Width with get() = wd and set(value) = wd <- value member this.Perimeter with get() = (len + wd) * 2.00 member this.Area with get() = len * wd type Circle() = let mutable radius = 0.00 member me.Radius with get() = radius and set(value) = radius <- value member me.Diameter with get() = radius * 2.00 member me.Circumference with get() = me.Diameter * 3.14156 member me.Area with get() = radius * radius * 3.14156 type BasketballCourt() = let mutable external = new Rectangle() let mutable central = new Circle() let mutable rar = 0.00 let mutable rh = 0.00 let mutable kw = 0.00 let mutable ftld = 0.00 let mutable b3pld = 0.00 member sport.Court with get() = external and set(value) = external <- value member sport.Center with get() = central and set(value) = central <- value member sport.RestrictedArcRadius with get() = rar and set(value) = rar <- value member sport.RimHeight with get() = rh and set(value) = rh <- value member sport.KeyWidth with get() = kw and set(value) = kw <- value member sport.FreeThrowLineDistance with get() = ftld and set(value) = ftld <- value member sport.B3PointLineDistanceFromBasket with get() = b3pld and set(value) = b3pld <- value let NBACourt = BasketballCourt() let NBA = Rectangle() NBA.Length <- 28.65 NBA.Width <- 15.24 NBACourt.Court <- NBA NBACourt.RimHeight <- 3.05; NBACourt.RestrictedArcRadius <- 1.22; let courtCenter = Circle() courtCenter.Radius <- 1.22; NBACourt.Center <- courtCenter NBACourt.B3PointLineDistanceFromBasket <- 1.22; NBACourt.KeyWidth <- 4.88; NBACourt.FreeThrowLineDistance <- 4.57; type Description = delegate of BasketballCourt -> unit let describe (court : BasketballCourt) = printfn "Basketball Court" printfn "_____________________________________________________" printfn "Court Measures ______________________________________" printfn " Length: %0.02f m" court.Court.Length printfn " Width: %0.02f m" court.Court.Width printfn " Perimeter: %0.02f m" court.Court.Perimeter printfn " Area: %0.02f m" court.Court.Area printfn "Central Circle Measures ____________________________" printfn " Radius: %0.02f m" court.Center.Radius printfn " Diameter: %0.02f m" court.Center.Diameter printfn " Circumference: %0.02f m" court.Center.Circumference printfn " Area: %0.02f m" court.Center.Area printfn "____________________________________________________" printfn "Restricted Arc Radius: %0.02f m" court.RestrictedArcRadius printfn "3-Point Line Distance From Basket: %0.02f m" court.B3PointLineDistanceFromBasket printfn "Key Width (Shaded Lane or Restricted Area: %0.02f m" court.KeyWidth printfn "Free-throw line distance from point on the floor directly below the backboard: %0.02f m" court.FreeThrowLineDistance printfn "____________________________________________________" let result = Description(describe) result.Invoke NBACourt
This would produce:
Basketball Court _____________________________________________________ Court Measures ______________________________________ Length: 28.65 m Width: 15.24 m Perimeter: 87.78 m Area: 436.63 m Central Circle Measures ____________________________ Radius: 1.22 m Diameter: 2.44 m Circumference: 7.67 m Area: 4.68 m ____________________________________________________ Restricted Arc Radius: 1.22 m 3-Point Line Distance From Basket: 1.22 m Key Width (Shaded Lane or Restricted Area: 4.88 m Free-throw line distance from point on the floor directly below the backboard: 4 .57 m ____________________________________________________ Press any key to close this window . . .
Although we passed a parameter based on a class, the parameter can actually be of any valid type, such as a record. Here is an example:
type RoadType = | Court | Street | Road | Avenue | Boulevard | StateRoad | StateHighway | Interstate | Unknown type Road = { Name : string Category : RoadType Distance : float Location : string } let USRoute1 = { Name = "U.S. Route 1"; Category = RoadType.Road; Distance = 2369.00; Location = "From FortKent, Maine To Key West, Florida"; } type RoadDescription = delegate of Road -> unit let describe (rd : Road) = printfn "Road System Database" printfn "=----------------------------------------------------=" printfn "Road Name: %s" rd.Name printfn "Category: %A" rd.Category printfn "Distance: %0.2f miles" rd.Distance printfn "Location: %s\n" rd.Location let desc = RoadDescription(describe) desc.Invoke USRoute1
This would produce:
Road System Database =----------------------------------------------------= Road Name: U.S. Route 1 Category: Road Distance: 2369.00 miles Location: From FortKent, Maine To Key West, Florida Press any key to close this window . . .
As mentioned for functions, you can pass a combination of parameters of various types such as a class and other classes, classes and objects, or classes and primitive types.
A Delegate that Returns an Object
As seen already, a delegate can return a value, and that value can be a type of object (class, record, etc). The type can be an existing class or you can create yor own. Of course, the associated function(s) must also return the same type of object. Everything else is done as we have done so far. Here is an example:
type Employee() = let mutable emplNbr = "" let mutable fn = "" let mutable ln = "" let mutable sal = 0.00 member this.EmployeeNumber with get() = emplNbr and set(value) = emplNbr <- value member this.FirstName with get() = fn and set(value) = fn <- value member this.LastName with get() = ln and set(value) = ln <- value member this.HourlySalary with get() = sal and set(value) = sal <- value type PayrollPresentation = delegate of unit -> Employee let createEmployeeRecord() = let empl : Employee = Employee() empl.EmployeeNumber <- "2080-4813" empl.FirstName <- "James" empl.LastName <- "Alexanders" empl.HourlySalary <- 22.25 empl let presentation = new PayrollPresentation(createEmployeeRecord) let empl = presentation.Invoke() printfn "Employee Payroll Summary" printfn "----------------------------------------------------" printfn "Employee #: %s" empl.EmployeeNumber printfn "Full Name: %s %s" empl.FirstName empl.LastName printfn "Hourly Salary: %0.02F" empl.HourlySalary printfn "----------------------------------------------------"
This would produce:
Employee Payroll Summary ---------------------------------------------------- Employee #: 2080-4813 Full Name: James Alexanders Hourly Salary: 22.25 ---------------------------------------------------- Press any key to close this window . . .
In the same way, you can create a delegate that takes any type of value of your choice and returns an object of a class type.
F# Support for Function Objects
Introduction
Instead of making you create your own delegates from scratch, the F# language provides its own and strong support for function objects. It does this in the concepts of function values and lambda expressions.
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, specify the signature of the function parameter: a name, followed by a column, the data type(s) of its argument(s), the -> operator, and the return type. Here is an example:
let display (show : unit -> unit) = . . .
In this case, we are creating a function named display. That primary function takes a parameter named show. This parameter is treated as a function. That function will take no parameter and will not return anything.
In the body of the primary function, you can use the parameter as a function. At a minimum, you can simply call it as a function. Here is an example:
let display (show : unit -> unit) = show()
Before calling the primary 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 display (show : unit -> unit) = show()
let present msg =
printfn "Welcome to the wonderful world of functional programming!"
When calling the primary function, pass the second function as argument in the placeholder of the function passed as parameter. Here is an example:
let display1 (show : unit -> unit) = show()
let present1 msg = printfn "Welcome to the wonderful world of functional programming!"
display present
This would produce:
Welcome to the wonderful world of functional programming!
If the function parameter must take a parameter, specify its type in the signature of the parameter, on the left side of the -> operator. Here is an example:
let display (show : string -> unit) = . . .
In most cases, you should pass another parameter to the primary function. That other parameter should (must) be the same type as the parameter of the function argument. In the body of the primary function, you can call the function parameter as a function. If you had passed an additional parameter to the primary function, you can pass it to the function parameter. Here is an example:
let display (show : string -> unit) message = show message;
Remember that you should always have a secondary function that actually implements the function parameter. The second function must take the same number of parameters and types as the function parameter. Here is an example:
let display (show : string -> unit) message = show message;
let present msg = printfn "Message: %s" msg;
When calling the primary function, remember to pass a secondary function as argument. Remember that you must pass an argument to that parameter. Here is an example:
let display (show : string -> unit) message = show message;
let present msg = printfn "Message: %s" msg;
display present "Welcome to the wonderful world of functional programming!"
Instead of returning unit as we have done so far, you can make the function parameter return any value of your choice. Other than that, you must follow the necessary rules of functions. Here is an example of a function parameter that takes a string and returns a string:
let display (show : string -> string) message = show message; let present msg = msg; let result = display present "Welcome to the wonderful world of functional programming!"; printfn "Message: %s" result
This would produce:
Message: Welcome to the wonderful world of functional programming!
You can pass as many parameters as you want to the primary function. In its body, use those additional parameters as you see fit. Here is an example of a function that takes three normal parameters in addition to a function parameter:
let createCatalog (description : string -> string) name teacher period = "Teacher:\t" + teacher + "\n" + description name + "\nSchedule:\t" + period; let describe crsName = "Course Name: " + crsName; let catalog = createCatalog describe "Introduction to Library Research Skills" " Dr. Emmanuelle Critenden" " 02/12/2015 - 04/06/2015"; printfn "School Catalog\n-----------------------------------------------------" printfn "%s" catalog
This would produce:
School Catalog --------------------------------------------------- Teacher: Dr. Emmanuelle Crittenden Course Name: Introduction to Library Research Skills Schedule: 02/12/2015 - 04/06/2015
You can pass as many function parameters as you want to a primary function. For any function parameter that is not void, you should pass an additional parameter to the primary function, to be used by the function parameter. In the body of the primary function, each function parameter can be used as a normal function that is being called.
Introduction to 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 type of function that is passed to another function as argument, as we saw about function parameters. This time, to create the function you are passing as argument, that is, to create the lambda expression, use the following formula:
fun | function parameter(s) -> expression
The expression starts with the fun or the function keyword. The function is not named. Instead, the fun or function 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 or primary function does. In that primary 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 parameter and another value as another parameter. The primary 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, the parameter passed to fun or function is an object of a class type. In this case, you should (must) specify the type of the parameter. To do this, put the parameter name and iTS type in parentheses separated by :.
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:
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 . . .
Active Patterns and Lambda Expressions
We had an introduction to active patterns. When it comes to active patterns, instead of passing an argument to the function, you can create a lambda expression in the body of the function. That lambda expression can take an argument. Here is an example:
let (|Calculate|) = fun x -> x * x * 3.14
Of course, you can specify the data type of the argument. Here is an example:
let (|Calculate|) = fun (x : float) -> x * x * 3.14
When calling the function, pass the desired value as argument. Here is an example:
let (|Calculate|) = fun (x : float) -> x * x * 3.14 let area = (|Calculate|) 25.50 printfn "Area of Circle: %0.04f" area
If necessary, the lambda expression can take as many arguments as you want. Here is an example:
let (|Calculate|) = fun x y -> x * y
let length = 48.79
let height = 33.63
let area = (|Calculate|) length height
printfn "Rectangle Characteristics"
printfn "----------------------"
printfn "Length: %0.02f" length
printfn "Height: %0.02f" height
printfn "Area: %0.04f" area
In the same way, the function can be called in a matching pattern with the right arguments. Here is an example:
let (|Calculate|) = fun x y -> x * y let length = 48.79 let height = 33.63 let area = (|Calculate|) length height match (|Calculate|) length height with | _ -> printfn "Rectangle Characteristics" printfn "----------------------" printfn "Length: %0.02f" length printfn "Height: %0.02f" height printfn "Area: %0.04f" area
Actions Delegates
Introduction
Although all or most .NET languages support delegates and lambda expressions, the .NET Framework provides its own support for delegates. It does this through various classes. Therefore, instead of making you create delegates from scratch, and to provide universal support for all .NET languages, the .NET Framework provides various pre-built or built-in delegates that you can use directly in your programs.
Creating a Simple Action
One of the built-in delegates of the .NET Framework is named Action. It is provided in various syntaxes. The Action delegate is defined in the System namespace of the mscorlib.dll library. You should include that namespace in the document of your program.
The primary type of a Action delegate you will use is for functions (called procedures in some other languages) that take no parameter and return nothing. Its signature is:
type Action = delegate of unit -> unit
Notice that the signature exactly resembles the one we saw in our introduction to delegates. This time, the name of the delegate is replaced with Action. Also notice that the delegate of expression is used, exactly as it was in our introduction to delegates. This means that an Action delegate is of type FSharpFunc. This also means that such a delegate receives all the members of that class, including the Invoke() method.
To create an action for the delegate, declare a variable. Since you would not have created a delegate, use Action to initialize the variable and add its parentheses. The rest is done as we saw already. This means that you should first create a function, or define a method, and pass it to the parentheses of Action.
Consider the simple example we saw in our introduction:
type TitleCreation = delegate of unit -> unit let getTitle() : unit = printfn "Introduction to F# Programming, Second Edition" let title = TitleCreation(getTitle) title.Invoke()
This would produce:
Introduction to F# Programming, Second Edition Press any key to close this window . . .
To use the Action deleegate, include the System namespace in your code file and replace the name of the delegate with Action. Here is an example:
open System let getTitle() : unit = printfn "Introduction to F# Programming, Second Edition" let title = Action(getTitle) title.Invoke()
If you want, you can include the new operator before Action. Here is an example:
open System
let getTitle() : unit =
printfn "Introduction to F# Programming, Second Edition"
let title = new Action(getTitle)
title.Invoke()
If you want to specify the data type of the variable, type : Action after the name of the variable. Here is an example:
open System
let getTitle() : unit =
printfn "Introduction to F# Programming, Second Edition"
let title : Action = new Action(getTitle)
title.Invoke()
An Action Delegate With Parameters
To support parameters passed to a delegate, the Action delegate is provided in many versions, each for a certain number of parameters. The primary version in this category uses the following signature:
type Action = delegate of obj:'T -> unit
This syntax is for a procedure (function) that takes one parameter and returns nothing. As you can see, the parameter is a generic type, meaning it can be any type such as a primitive type. When calling Action, you must specify the type of the parameter. To do this, after Action, add the <> operator. Inside, enter the type of the parameter. Here is an example:
Action<string>()
Everything else is done as seen so far. As mentioned already, you can use the Action delegate that takes one parameter and the parameter can be a primitive type. Here is an example:
open System
let describe str =
printfn "Course Name: %s" str
let desc = new Action<string>(describe)
desc.Invoke "Enterprise Database Design"
This would produce:
Course Name: Enterprise Database Design Press any key to close this window . . .
The parameter can be a class type. Here is an example:
open System
type Circle() =
let mutable radius = 0.00
member me.Radius with get() = radius and set(value) = radius <- value
member this.Diameter with get() = radius * 2.00
member this.Circumference with get() = this.Diameter * 3.14156
member this.Area with get() = radius * radius * 3.14156
let describe (circle : Circle) =
printfn "Circle Characteristics"
printfn "---------------------------"
printfn "Radius: %0.02f" circle.Radius
printfn "Diameter: %0.02f" circle.Diameter
printfn "Circumference: %f" circle.Circumference
printfn "Area: %f\n" circle.Area
let round = Circle()
round.Radius <- 48.06
let result = Action<Circle>(describe)
result.Invoke round
This would produce:
Circle Characteristics --------------------------- Radius: 48.06 Diameter: 96.12 Circumference: 301.966747 Area: 7256.260935 Press any key to close this window . . .
The parameter of an action can be another type such as a record. Here is an example:
open System type RoadType = | Court | Street | Road | Avenue | Boulevard | StateRoad | StateHighway | Interstate | Unknown type Road = { Name : string Category : RoadType Distance : float Location : string } let USRoute1 = { Name = "U.S. Route 1"; Category = RoadType.Road; Distance = 2369.00; Location = "From FortKent, Maine To Key West, Florida"; } let describe (rd : Road) = printfn "Road System Database" printfn "=----------------------------------------------------=" printfn "Road Name: %s" rd.Name printfn "Category: %A" rd.Category printfn "Distance: %0.2f miles" rd.Distance printfn "Location: %s\n" rd.Location let desc = Action<Road>(describe) desc.Invoke USRoute1
This would produce:
Road System Database =----------------------------------------------------= Road Name: U.S. Route 1 Category: Road Distance: 2369.00 miles Location: From FortKent, Maine To Key West, Florida Press any key to close this window . . .
The method of a class can be passed to an Action delegate. Here is an example:
open System
type EmploymentStatus =
| Unknown = 0
| FullTime = 1
| PartTime = 2
| Intern = 3
| Seasonal = 4
type Employee(emplNbr, fname, lname, status, salary) =
member val EmployeeNumber = emplNbr with get, set
member val FirstName = fname with get, set
member val LastName = lname with get, set
member val Status = status with get, set
member val HourlySalary = salary with get, set
member this.Present() : unit =
printfn "Employee Payroll Summary"
printfn "----------------------------------------------------"
printfn "Employee #: %s" this.EmployeeNumber
printfn "Full Name: %s %s" this.FirstName this.LastName
printfn "Status: %A" this.Status
printfn "Hourly Salary: %0.02F" this.HourlySalary
printfn "----------------------------------------------------"
let empl = Employee("7092-3094", "Rose", "Crittenden", EmploymentStatus.FullTime, 24.05)
let resume = Action(empl.Present)
resume.Invoke()
This would produce:
Employee Payroll Summary ---------------------------------------------------- Employee #: 7092-3094 Full Name: Rose Crittenden Status: FullTime Hourly Salary: 24.05 ---------------------------------------------------- Press any key to close this window . . .
To support the parameters passed to a procedure, there are various versions of the Action delegate. To specify the parameters of an Action delegate, in its <> operator, enter the parameter types separated by commas. Here is an example:
Action<int, string>()
In the parentheses, pass the name of the function that implements the delegate.
Functions Delegates
Introduction
The Action delegate is used for unit functions (also called procedures) or class methods; those are functions and methods that don't return a value. To support functions and methods that return a value, the .NET Framework provides a delegate named Func. As seen for the Action type, the Func delegate is delivered in various versions that take different parameters.
The most fundamental version of a function delegate has the following signature:
type Func = delegate of unit -> 'TResult
Notice that instead of the Action word, Func is used. This version is for a function or method that takes no parameter but returns a value. Notice that the return value is a generic type. This means that you must specify the type of value that the function or method must return. To do this, enter the type after the Func name between < and >. Everthing else is as we saw for the Action delegate. Remember that the function returns a value. You can get that value and store it in a variable if you want. Here is an example:
open System
let introduce() : string =
"Welcome to Four-Corner restaurant. We serve the best exotic meals in the region. " +
"Our selection includes soups, sauce, meals, and appetizers. During the week, " +
"from Monday to Friday, we serve the Lunch Special when the prices of most of " +
"meals are reduced. Come and try our tastes. You will be delighted."
let description = Func<string>(introduce)
let result = description.Invoke();
printfn "Restaurant Introduction: %s" result
This would produce:
Restaurant Introduction: Welcome to Four-Corner restaurant. We serve the best ex otic meals in the region. Our selection includes soups, sauce, meals, and appeti zers. During the week, from Monday to Friday, we serve the Lunch Special when th e prices of most of meals are reduced. Come and try our tastes. You will be deli ghted. Press any key to close this window . . .
If you don't need to use the return value many times, you don't have to store it in a variable. You can directly call the Invoke() method where the return value is needed. Here is an example:
open System
let introduce() : string =
"Welcome to Four-Corner restaurant. We serve the best exotic meals in the region. " +
"Our selection includes soups, sauce, meals, and appetizers. During the week, " +
"from Monday to Friday, we serve the Lunch Special when the prices of most of " +
"meals are reduced. Come and try our tastes. You will be delighted."
let description = Func<string>(introduce)
printfn "Restaurant Introduction: %s" (description.Invoke())
In the same way, you don't have to formally declare a variable for Func. You can directly use it where needed. Here is an example:
printfn "Restaurant Introduction: %s" ((Func<string>(introduce)).Invoke())
As its name indicates, the primary purpose of a function delegate is to return a value. The value can be a primitive type or a class type. Here is an example:
open System
type Employee() =
let mutable emplNbr = ""
let mutable fn = ""
let mutable ln = ""
let mutable sal = 0.00
member this.EmployeeNumber with get() = emplNbr and set(value) = emplNbr <- value
member this.FirstName with get() = fn and set(value) = fn <- value
member this.LastName with get() = ln and set(value) = ln <- value
member this.HourlySalary with get() = sal and set(value) = sal <- value
let createEmployeeRecord() =
let empl : Employee = Employee()
empl.EmployeeNumber <- "2080-4813"
empl.FirstName <- "James"
empl.LastName <- "Alexanders"
empl.HourlySalary <- 22.25
empl
let presentation = Func<Employee>(createEmployeeRecord)
let empl = presentation.Invoke()
printfn "Employee Payroll Summary"
printfn "----------------------------------------------------"
printfn "Employee #: %s" empl.EmployeeNumber
printfn "Full Name: %s %s" empl.FirstName empl.LastName
printfn "Hourly Salary: %0.02F" empl.HourlySalary
printfn "----------------------------------------------------"
This would produce:
Employee Payroll Summary ---------------------------------------------------- Employee #: 2080-4813 Full Name: James Alexanders Hourly Salary: 22.25 ---------------------------------------------------- Press any key to close this window . . .
Characteristics of Function Delegates
We already know how to specify the return value of a function. One of the characteristics of delegates is that they can take parameters. This also applies to Functions. To specify the parameter of a Func delegate, in its <> operator, after <, enter the parameter type, followed by a comma, and the return type. Here is an example:
Func<int, string>()
In the parentheses, pass the name of the function that implements the delegate. When calling the Invoke() function, pass an argument that is the type specified in Func. Here is an example:
open System
let introduce() : string =
"Welcome to Four-Corner restaurant. We serve the best exotic meals in the region. " +
"Our selection includes soups, sauce, meals, and appetizers. During the week, " +
"from Monday to Friday, we serve the Lunch Special when the prices of most of " +
"meals are reduced. Come and try our tastes. You will be delighted."
let describeMeal selection : string =
match selection with
| 1 -> "Sweet and Sour Chicken is cooked from a combination of " +
"vegetable oil, chicken breast, brown sugar, wine vinegar, salt pepper, green " +
"pepper, cornstarch, and water. water. We serve it both at noon (lunch) and " +
"evening (dinner). At lunch, we serve it both as Lunch Special (5.95) and " +
"regular lunch (8.95). In the evening and weekend (all times), we serve it for 9.95."
| 2 -> "Mongolian Beef is cooked in a mixure of flank steak, vegetable " +
"oil, eggs, scallion slices, garlic, rice noodles, cornstarh, sugar, ground " +
"black pepper, oy sauce, and water. We serve it both at noon (lunch) and " +
"evening (dinner). At lunch, Lunch Special costs 5.95 and regular lunch " +
"costs 8.95. In the evening and weekend (all times), we serve it for 9.95."
| 3 -> "Our Cashew Shrimp meal is made from shelled srimp, vegetable " +
"oil, cashews, carrots, diced celery, water chestnut, and rice wine. In " +
"addition, we use checken broth, sesame oil, cornstarch, soy sauce, and " +
"oyster sauce. We serve Cashew Shrimp everyday for lunch and dinner. Lunch " +
"special costs 7.25. Evening diner and weekend meals cost 10.55"
| _-> "The value you provided is not a valid selection."
let description = Func<int, string>(describeMeal)
let result = description.Invoke(2)
printfn "Restaurant Introduction: %s" ((Func<string>(introduce)).Invoke())
printfn "Description of Meal Selected\n%s" result
This would produce:
Restaurant Introduction: Welcome to Four-Corner restaurant. We serve the best ex otic meals in the region. Our selection includes soups, sauce, meals, and appeti zers. During the week, from Monday to Friday, we serve the Lunch Special when th e prices of most of meals are reduced. Come and try our tastes. You will be deli ghted. Description of Meal Selected Mongolian Beef is cooked in a mixure of flank steak, vegetable oil, eggs, scalli on slices, garlic, rice noodles, cornstarh, sugar, ground black pepper, oy sauce , and water. We serve it both at noon (lunch) and evening (dinner). At lunch, Lu nch Special costs 5.95 and regular lunch costs 8.95. In the evening and weekend (all times), we serve it for 9.95. Press any key to close this window . . .
In the same way, a function can take more than one parameter and you must indicate their types. As mentioned already, the Func delegate is available in various versions for different numbers of parameters. To specify the types of the parameters, after the < operator of Func, enter the types separated by commas, and end with the return type of the function. Here is an example:
open System
type TimePeriod =
| LunchSpecial
| RegularLunch
| Dinner
let introduce() : string =
"Welcome to Four-Corner restaurant. We serve the best exotic meals in the region. " +
"Our selection includes soups, sauce, meals, and appetizers. During the week, " +
"from Monday to Friday, we serve the Lunch Special when the prices of most of " +
"meals are reduced. Come and try our tastes. You will be delighted."
let describeMeal selection : string =
match selection with
| "SSC" -> "Sweet and Sour Chicken is cooked from a combination of " +
"vegetable oil, chicken breast, brown sugar, wine vinegar, salt pepper, green " +
"pepper, cornstarch, and water. water. We serve it both at noon (lunch) and " +
"evening (dinner). At lunch, we serve it both as Lunch Special (5.95) and " +
"regular lunch (8.95). In the evening and weekend (all times), we serve it for 9.95."
| "MNB" -> "Mongolian Beef is cooked in a mixure of flank steak, vegetable " +
"oil, eggs, scallion slices, garlic, rice noodles, cornstarh, sugar, ground " +
"black pepper, oy sauce, and water. We serve it both at noon (lunch) and " +
"evening (dinner). At lunch, Lunch Special costs 5.95 and regular lunch " +
"costs 8.95. In the evening and weekend (all times), we serve it for 9.95."
| "CSH" -> "Our Cashew Shrimp meal is made from shelled srimp, vegetable " +
"oil, cashews, carrots, diced celery, water chestnut, and rice wine. In " +
"addition, we use checken broth, sesame oil, cornstarch, soy sauce, and " +
"oyster sauce. We serve Cashew Shrimp everyday for lunch and dinner. Lunch " +
"special costs 7.25. Evening diner and weekend meals cost 10.55"
| _ -> "The value you provided is not a valid selection."
let selectMeal (period : TimePeriod) choice : float =
match period with
| LunchSpecial ->
match choice with
| 1 -> 5.95 // Lunch Special
| 2 -> 6.45 // Regular Lunch
| 3 -> 7.25 // Dinner and Weekend
| _ -> 0.00 // Unknown Choice
| RegularLunch ->
match choice with
| 1 -> 8.95 // Lunch Special
| 2 -> 10.50 // Regular Lunch
| 3 -> 9.65 // Dinner and Weekend
| _ -> 0.00 // Unknown Choice
| Dinner ->
match choice with
| 1 -> 9.95 // Lunch Special
| 2 -> 12.50 // Regular Lunch
| 3 -> 9.65 // Dinner and Weekend
| _ -> 0.00 // Unknown Choice
let selection = Func<TimePeriod, int, float>(selectMeal)
let cost = selection.Invoke(LunchSpecial, 2)
printfn "Restaurant Introduction: %s" ((Func<string>(introduce)).Invoke())
printfn "Description of Meal Selected\n%s" ((Func<string, string>(describeMeal)).Invoke("MNB"))
printfn "Meal Price: %0.02F" cost
This would produce:
Restaurant Introduction: Welcome to Four-Corner restaurant. We serve the best ex otic meals in the region. Our selection includes soups, sauce, meals, and appeti zers. During the week, from Monday to Friday, we serve the Lunch Special when th e prices of most of meals are reduced. Come and try our tastes. You will be deli ghted. Description of Meal Selected Mongolian Beef is cooked in a mixure of flank steak, vegetable oil, eggs, scalli on slices, garlic, rice noodles, cornstarh, sugar, ground black pepper, oy sauce , and water. We serve it both at noon (lunch) and evening (dinner). At lunch, Lu nch Special costs 5.95 and regular lunch costs 8.95. In the evening and weekend (all times), we serve it for 9.95. Meal Price: 6.45 Press any key to close this window . . .
Remember that the parameters are generic and can be any type. In fact, you can use a combination of classes and primitive types.
A function delegate uses the same characteristics of regular functions and methods. For example, a function delegate can be passed as parameter to a function or a method. Here is an example:
open System
let initialyze courseName credits =
courseName + "(" + (string credits) + ")"
let createCatalog (init : Func<string, int, string>) name title credits =
let course = new Func<string, int, string>(initialyze)
name + ": " + course.Invoke(title, credits)
let catalogue = Func<Func<string, int, string>, string, string, int, string>(createCatalog)
let init = Func<string, int, string>(initialyze)
let result = catalogue.Invoke(init, "CMIS 226", "Enterprise Database Design", 3)
printfn "Course Decription: %s" result
This would produce:
Course Decription: CMIS 226: Enterprise Database Design(3) Press any key to close this window . . .
Remember that you can omit declaring variables that you don't need (making code difficult to read). Here is an example:
open System
let initialyze courseName credits =
courseName + "(" + (string credits) + ")"
let createCatalog (init : Func<string, int, string>) name title credits =
let course = new Func<string, int, string>(initialyze)
name + ": " + course.Invoke(title, credits)
let result = (Func<Func<string, int, string>, string, string, int, string>(createCatalog)).Invoke(Func<string, int, string>(initialyze), "CMIS 226", "Enterprise Database Design", 3)
printfn "Course Decription: %s" result
This would produce:
Course Decription: CMIS 226: Enterprise Database Design(3) Press any key to close this window . . .
As another characteiristic, a method of a class can be passed to a function delegate. Here is an example:
open System
type EmploymentStatus =
| Unknown = 0
| FullTime = 1
| PartTime = 2
| Intern = 3
| Seasonal = 4
type Employee(emplNbr, fname, lname, status, salary) =
member val EmployeeNumber = emplNbr with get, set
member val FirstName = fname with get, set
member val LastName = lname with get, set
member val Status = status with get, set
member val HourlySalary = salary with get, set
member this.CalculateSalary salaryIsFixed timeWorked : float =
if salaryIsFixed = true then
salary * 40.00
else
salary * timeWorked
let empl = Employee("7092-3094", "Rose", "Crittenden", EmploymentStatus.FullTime, 24.05)
let result = Func<bool, float, float>(empl.CalculateSalary)
printfn "Employee Payroll Summary"
printfn "----------------------------------------------------"
printfn "Employee #: %s" empl.EmployeeNumber
printfn "Full Name: %s %s" empl.FirstName empl.LastName
printfn "Status: %A" empl.Status
printfn "Hourly Salary: %0.02F" empl.HourlySalary
printfn "----------------------------------------------------"
printfn "Weekly Salary: %0.02F" (result.Invoke(false, 44.50))
This would produce:
Employee Payroll Summary ---------------------------------------------------- Employee #: 7092-3094 Full Name: Rose Crittenden Status: FullTime Hourly Salary: 24.05 ---------------------------------------------------- Weekly Salary: 1070.23 Press any key to close this window . . .
|
|||
Previous | Copyright © 2015-2024, FunctionX | Thursday 02 November 2024 | Next |
|