作为一类值的函数 (F#)
函数编程语言的定义特征是将函数提升到一类状态。您应当能够对函数执行可对其他内置类型的值执行的任何操作,并且只需一般程度的工作量就能够完成此操作。
一类状态的典型度量包括:
是否可以将标识符绑定到值?也就是说,是否可以为它指定一个名称?
是否可以将值存储在诸如列表之类的数据结构中?
是否可以在函数调用中将值作为参数传递?
是否可以将值作为函数调用的值返回?
最后两个度量定义的对象称为高阶运算或高阶函数。高阶函数接受作为参数的函数,并将函数作为函数调用的值返回。这些操作支持将这种函数编程主体作为映射函数和函数组合。
为该值指定名称
如果函数是一类值,您必须能够对其进行命名,就像您可以对整数、字符串和其他内置类型命名一样。这在函数编程语言中称为将标识符绑定到值。F# 使用 let 表达式将名称绑定到值: let <identifier> = <value>。以下代码显示了两个示例。
// Integer and string.
let num = 10
let str = "F#"
您可以轻松地命名函数。下面的示例通过将标识符 squareIt 绑定到 lambda 表达式fun n -> n * n 来定义名为 squareIt 的函数。函数 squareIt 具有一个参数 n,它返回该参数的平方。
let squareIt = fun n -> n * n
F# 提供了以下更简洁的语法,可以在使用较少键入的情况下获得相同的结果。
let squareIt2 n = n * n
后续示例大多使用第一个样式 let <function-name> = <lambda-expression>,以强调函数声明和其他类型值的声明之间的相似之处。不过,也可以使用简洁语法编写所有命名的函数。某些示例是用两种方法编写的。
将值存储在数据结构中
一类值可以存储在数据结构中。下面的代码显示在列表中和元组中存储值的示例。
// Lists.
// Storing integers and strings.
let integerList = [ 1; 2; 3; 4; 5; 6; 7 ]
let stringList = [ "one"; "two"; "three" ]
// You cannot mix types in a list. The following declaration causes a
// type-mismatch compiler error.
//let failedList = [ 5; "six" ]
// In F#, functions can be stored in a list, as long as the functions
// have the same signature.
// Function doubleIt has the same signature as squareIt, declared previously.
//let squareIt = fun n -> n * n
let doubleIt = fun n -> 2 * n
// Functions squareIt and doubleIt can be stored together in a list.
let funList = [ squareIt; doubleIt ]
// Function squareIt cannot be stored in a list together with a function
// that has a different signature, such as the following body mass
// index (BMI) calculator.
let BMICalculator = fun ht wt ->
(float wt / float (squareIt ht)) * 703.0
// The following expression causes a type-mismatch compiler error.
//let failedFunList = [ squareIt; BMICalculator ]
// Tuples.
// Integers and strings.
let integerTuple = ( 1, -7 )
let stringTuple = ( "one", "two", "three" )
// A tuple does not require its elements to be of the same type.
let mixedTuple = ( 1, "two", 3.3 )
// Similarly, function elements in tuples can have different signatures.
let funTuple = ( squareIt, BMICalculator )
// Functions can be mixed with integers, strings, and other types in
// a tuple. Identifier num was declared previously.
//let num = 10
let moreMixedTuple = ( num, "two", 3.3, squareIt )
为了验证元组中存储的函数名称的实际计算结果是否为函数,下面的示例使用 fst 和 snd 运算符提取 funAndArgTuple 元组中的第一个和第二个元素。元组中的第一个元素为 squareIt,第二个元素为 num。在上一示例中,标识符 num 绑定到整数 10,它是 squareIt 函数的有效参数。第二个表达式将元组中的第一个元素应用到元组中的第二个元素:squareIt num。
// You can pull a function out of a tuple and apply it. Both squareIt and num
// were defined previously.
let funAndArgTuple = (squareIt, num)
// The following expression applies squareIt to num, returns 100, and
// then displays 100.
System.Console.WriteLine((fst funAndArgTuple)(snd funAndArgTuple))
同样,就像标识符 num 和整数 10 可以互换使用一样,标识符 squareIt 和 lambda 表达式 fun n -> n * n 也可以互换。
// Make a list of values instead of identifiers.
let funAndArgTuple2 = ((fun n -> n * n), 10)
// The following expression applies a squaring function to 10, returns
// 100, and then displays 100.
System.Console.WriteLine((fst funAndArgTuple2)(snd funAndArgTuple2))
将值作为参数传递
如果值在语言中具有一类状态,则可以将它作为参数传递给函数。例如,常见的做法是将整数和字符串作为参数传递。下面的代码演示 F# 中作为参数传递的整数和字符串。
// An integer is passed to squareIt. Both squareIt and num are defined in
// previous examples.
//let num = 10
//let squareIt = fun n -> n * n
System.Console.WriteLine(squareIt num)
// String.
// Function repeatString concatenates a string with itself.
let repeatString = fun s -> s + s
// A string is passed to repeatString. HelloHello is returned and displayed.
let greeting = "Hello"
System.Console.WriteLine(repeatString greeting)
如果函数有一类状态,您必须能够以相同的方式将它们作为参数传递。请记住,这是高阶函数的第一个特征。
在下面的示例中,函数 applyIt 有两个参数:op 和 arg。如果发送到 arg 的函数中有一个对应于 op 的形参和该函数的一个相应实参,则该函数返回将 op 应用到 arg 的结果。在下面的示例中,函数参数和整型参数都使用它们的名称以相同的方式发送。
// Define the function, again using lambda expression syntax.
let applyIt = fun op arg -> op arg
// Send squareIt for the function, op, and num for the argument you want to
// apply squareIt to, arg. Both squareIt and num are defined in previous
// examples. The result returned and displayed is 100.
System.Console.WriteLine(applyIt squareIt num)
// The following expression shows the concise syntax for the previous function
// definition.
let applyIt2 op arg = op arg
// The following line also displays 100.
System.Console.WriteLine(applyIt2 squareIt num)
将一个函数作为另一个函数的参数发送的功能将常见抽象基于函数编程语言,例如映射操作或筛选操作。例如,映射操作是一个高阶函数,它捕获由函数共享的计算,这些函数单步执行某个列表,对每个元素执行一些操作,然后返回结果列表。您可能要递增整数列表中的每个元素,对每个元素求平方,或者将字符串列表中的每个元素更改为大写。计算中易于出错的部分是单步执行列表并生成返回结果列表的递归过程。该部分是在映射函数中捕获的。必须为特定应用程序编写的全部内容就是要分别应用于每个列表元素的函数(添加、求平方、更改大小写)。就像上例中将 squareIt 发送到 applyIt 一样,该函数作为参数发送到映射函数。
F# 提供大多数集合类型(包括列表、数组和集)的映射方法。下面的示例使用列表。语法为 List.map <the function> <the list>。
// List integerList was defined previously:
//let integerList = [ 1; 2; 3; 4; 5; 6; 7 ]
// You can send the function argument by name, if an appropriate function
// is available. The following expression uses squareIt.
let squareAll = List.map squareIt integerList
// The following line displays [1; 4; 9; 16; 25; 36; 49]
printfn "%A" squareAll
// Or you can define the action to apply to each list element inline.
// For example, no function that tests for even integers has been defined,
// so the following expression defines the appropriate function inline.
// The function returns true if n is even; otherwise it returns false.
let evenOrNot = List.map (fun n -> n % 2 = 0) integerList
// The following line displays [false; true; false; true; false; true; false]
printfn "%A" evenOrNot
有关更多信息,请参见列表 (F#)。
从函数调用返回值
最后,如果函数在某种语言中具有一类状态,您必须能够将其作为函数调用的值返回,就像返回其他类型(如整数和字符串)一样。
以下函数调用返回并显示整数。
// Function doubleIt is defined in a previous example.
//let doubleIt = fun n -> 2 * n
System.Console.WriteLine(doubleIt 3)
System.Console.WriteLine(squareIt 4)
以下函数调用返回字符串。
// str is defined in a previous section.
//let str = "F#"
let lowercase = str.ToLower()
以下以内联方式声明的函数调用返回一个布尔值。显示的值为 True。
System.Console.WriteLine((fun n -> n % 2 = 1) 15)
能够将函数作为函数调用的值返回是高阶函数的第二个特征。在下面的示例中,checkFor 被定义为一个函数,该函数带有一个参数 item,并返回一个新函数作为其值。返回的函数采用列表作为其参数 lst,然后在 lst 中搜索 item。如果存在 item,则函数返回 true。如果不存在 item,则函数返回 false。像在上一节中一样,下面的代码使用提供的列表函数 List.exists 来搜索列表。
let checkFor item =
let functionToReturn = fun lst ->
List.exists (fun a -> a = item) lst
functionToReturn
下面的代码使用 checkFor 创建一个新函数,该函数带有一个参数(即一个列表)并在该列表中搜索 7。
// integerList and stringList were defined earlier.
//let integerList = [ 1; 2; 3; 4; 5; 6; 7 ]
//let stringList = [ "one"; "two"; "three" ]
// The returned function is given the name checkFor7.
let checkFor7 = checkFor 7
// The result displayed when checkFor7 is applied to integerList is True.
System.Console.WriteLine(checkFor7 integerList)
// The following code repeats the process for "seven" in stringList.
let checkForSeven = checkFor "seven"
// The result displayed is False.
System.Console.WriteLine(checkForSeven stringList)
下面的示例使用 F# 中函数的一类状态声明一个函数 compose,该函数返回两个函数参数的组合。
// Function compose takes two arguments. Each argument is a function
// that takes one argument of the same type. The following declaration
// uses lambda expresson syntax.
let compose =
fun op1 op2 ->
fun n ->
op1 (op2 n)
// To clarify what you are returning, use a nested let expression:
let compose2 =
fun op1 op2 ->
// Use a let expression to build the function that will be returned.
let funToReturn = fun n ->
op1 (op2 n)
// Then just return it.
funToReturn
// Or, integrating the more concise syntax:
let compose3 op1 op2 =
let funToReturn = fun n ->
op1 (op2 n)
funToReturn
说明 |
---|
有关甚至更短的版本,请参见下一节“扩充函数”。 |
下面的代码将两个函数作为参数发送给 compose,这两个函数带有相同类型的单个参数。返回值是由两个函数参数构成的新函数。
// Functions squareIt and doubleIt were defined in a previous example.
let doubleAndSquare = compose squareIt doubleIt
// The following expression doubles 3, squares 6, and returns and
// displays 36.
System.Console.WriteLine(doubleAndSquare 3)
let squareAndDouble = compose doubleIt squareIt
// The following expression squares 3, doubles 9, returns 18, and
// then displays 18.
System.Console.WriteLine(squareAndDouble 3)
说明 |
---|
F# 提供了两个运算符 << 和 >>,它们构成函数。例如,let squareAndDouble2 = doubleIt << squareIt 等同于上例中的 let squareAndDouble = compose doubleIt squareIt。 |
下面的示例将函数作为函数调用的值返回,它将创建一个简单的猜测游戏。若要创建一个游戏,请调用 makeGame,并将希望某人猜测的值作为 target 发送。从函数 makeGame 返回的值是一个函数,它带有一个参数 (guess),并报告 guess 是否正确。
let makeGame target =
// Build a lambda expression that is the function that plays the game.
let game = fun guess ->
if guess = target then
System.Console.WriteLine("You win!")
else
System.Console.WriteLine("Wrong. Try again.")
// Now just return it.
game
下面的代码调用 makeGame,并将值 7 作为 target 发送。标识符 playGame 绑定到返回的 lambda 表达式。因此,playGame 是一个函数,它采用 guess 的值作为它的一个参数。
let playGame = makeGame 7
// Send in some guesses.
playGame 2
playGame 9
playGame 7
// Output:
// Wrong. Try again.
// Wrong. Try again.
// You win!
// The following game specifies a character instead of an integer for target.
let alphaGame = makeGame 'q'
alphaGame 'c'
alphaGame 'r'
alphaGame 'j'
alphaGame 'q'
// Output:
// Wrong. Try again.
// Wrong. Try again.
// Wrong. Try again.
// You win!
扩充函数
通过利用 F# 函数声明中的隐式扩充,可以更简洁地编写上一节中的许多示例。扩充是将具有多个参数的函数转换为一系列嵌入式函数(每个嵌入式函数都具有一个参数)的过程。在 F# 中,具有多个参数的函数都会被扩充。例如,如以下简洁样式所示,可以使用三个参数编写上一节中的 compose。
let compose4 op1 op2 n = op1 (op2 n)
但是,结果是一个具有一个参数的函数,该参数又返回一个具有一个参数的函数,而这个参数又返回另一个具有一个参数的函数,如 compose4curried 中所示。
let compose4curried =
fun op1 ->
fun op2 ->
fun n -> op1 (op2 n)
可以通过多种方法访问此函数。下面每个示例返回并显示 18。在任一示例中,可以将 compose4 替换为 compose4curried。
// Access one layer at a time.
System.Console.WriteLine(((compose4 doubleIt) squareIt) 3)
// Access as in the original compose examples, sending arguments for
// op1 and op2, then applying the resulting function to a value.
System.Console.WriteLine((compose4 doubleIt squareIt) 3)
// Access by sending all three arguments at the same time.
System.Console.WriteLine(compose4 doubleIt squareIt 3)
若要验证函数仍像之前一样工作,请重试原始测试用例。
let doubleAndSquare4 = compose4 squareIt doubleIt
// The following expression returns and displays 36.
System.Console.WriteLine(doubleAndSquare4 3)
let squareAndDouble4 = compose4 doubleIt squareIt
// The following expression returns and displays 18.
System.Console.WriteLine(squareAndDouble4 3)
说明 |
---|
可以通过将参数包括在元组中来限制扩充。有关更多信息,请参见形参和实参 (F#)中的“形参模式”。 |
下面的示例使用隐式扩充编写 makeGame 的简短版本。在该格式下,有关 makeGame 如何构造和返回 game 函数的详细信息不太明确,但您可以使用结果相同的原始测试用例进行验证。
let makeGame2 target guess =
if guess = target then
System.Console.WriteLine("You win!")
else
System.Console.WriteLine("Wrong. Try again.")
let playGame2 = makeGame2 7
playGame2 2
playGame2 9
playGame2 7
let alphaGame2 = makeGame2 'q'
alphaGame2 'c'
alphaGame2 'r'
alphaGame2 'j'
alphaGame2 'q'
有关扩充的更多信息,请参见函数 (F#)中的“参数的部分应用”。
标识符和函数定义可以互换
上例中的变量名 num 的计算结果为整数 10,num 有效并不为奇,因为 10 也是有效的。函数标识符和它们的值也是如此:在可以使用函数名称的任何位置,都可以使用函数绑定到的 lambda 表达式。
下面的示例定义一个称为 isNegative 的 Boolean 函数,然后互换使用函数名称和函数定义。接下来的三个示例都返回并显示 False。
let isNegative = fun n -> n < 0
// This example uses the names of the function argument and the integer
// argument. Identifier num is defined in a previous example.
//let num = 10
System.Console.WriteLine(applyIt isNegative num)
// This example substitutes the value that num is bound to for num, and the
// value that isNegative is bound to for isNegative.
System.Console.WriteLine(applyIt (fun n -> n < 0) 10)
若要进一步操作,请用 applyIt 绑定到的值来替代 applyIt。
System.Console.WriteLine((fun op arg -> op arg) (fun n -> n < 0) 10)
函数是 F# 中的一类值
上面章节中的示例表明,F# 中的函数满足成为 F# 中的一类值的条件:
可以将标识符绑定到函数定义。
let squareIt = fun n -> n * n
可以将函数存储在数据结构中。
let funTuple2 = ( BMICalculator, fun n -> n * n )
可以将函数作为参数传递。
let increments = List.map (fun n -> n + 1) [ 1; 2; 3; 4; 5; 6; 7 ]
可以将函数作为函数调用的值返回。
let checkFor item = let functionToReturn = fun lst -> List.exists (fun a -> a = item) lst functionToReturn
有关 F# 的更多信息,请参见 Visual Studio 2012 中 Visual F# 的新增功能或 F# 语言参考。
示例
说明
下面的代码包含此主题中的所有示例。
代码
// ** GIVE THE VALUE A NAME **
// Integer and string.
let num = 10
let str = "F#"
let squareIt = fun n -> n * n
let squareIt2 n = n * n
// ** STORE THE VALUE IN A DATA STRUCTURE **
// Lists.
// Storing integers and strings.
let integerList = [ 1; 2; 3; 4; 5; 6; 7 ]
let stringList = [ "one"; "two"; "three" ]
// You cannot mix types in a list. The following declaration causes a
// type-mismatch compiler error.
//let failedList = [ 5; "six" ]
// In F#, functions can be stored in a list, as long as the functions
// have the same signature.
// Function doubleIt has the same signature as squareIt, declared previously.
//let squareIt = fun n -> n * n
let doubleIt = fun n -> 2 * n
// Functions squareIt and doubleIt can be stored together in a list.
let funList = [ squareIt; doubleIt ]
// Function squareIt cannot be stored in a list together with a function
// that has a different signature, such as the following body mass
// index (BMI) calculator.
let BMICalculator = fun ht wt ->
(float wt / float (squareIt ht)) * 703.0
// The following expression causes a type-mismatch compiler error.
//let failedFunList = [ squareIt; BMICalculator ]
// Tuples.
// Integers and strings.
let integerTuple = ( 1, -7 )
let stringTuple = ( "one", "two", "three" )
// A tuple does not require its elements to be of the same type.
let mixedTuple = ( 1, "two", 3.3 )
// Similarly, function elements in tuples can have different signatures.
let funTuple = ( squareIt, BMICalculator )
// Functions can be mixed with integers, strings, and other types in
// a tuple. Identifier num was declared previously.
//let num = 10
let moreMixedTuple = ( num, "two", 3.3, squareIt )
// You can pull a function out of a tuple and apply it. Both squareIt and num
// were defined previously.
let funAndArgTuple = (squareIt, num)
// The following expression applies squareIt to num, returns 100, and
// then displays 100.
System.Console.WriteLine((fst funAndArgTuple)(snd funAndArgTuple))
// Make a list of values instead of identifiers.
let funAndArgTuple2 = ((fun n -> n * n), 10)
// The following expression applies a squaring function to 10, returns
// 100, and then displays 100.
System.Console.WriteLine((fst funAndArgTuple2)(snd funAndArgTuple2))
// ** PASS THE VALUE AS AN ARGUMENT **
// An integer is passed to squareIt. Both squareIt and num are defined in
// previous examples.
//let num = 10
//let squareIt = fun n -> n * n
System.Console.WriteLine(squareIt num)
// String.
// Function repeatString concatenates a string with itself.
let repeatString = fun s -> s + s
// A string is passed to repeatString. HelloHello is returned and displayed.
let greeting = "Hello"
System.Console.WriteLine(repeatString greeting)
// Define the function, again using lambda expression syntax.
let applyIt = fun op arg -> op arg
// Send squareIt for the function, op, and num for the argument you want to
// apply squareIt to, arg. Both squareIt and num are defined in previous
// examples. The result returned and displayed is 100.
System.Console.WriteLine(applyIt squareIt num)
// The following expression shows the concise syntax for the previous function
// definition.
let applyIt2 op arg = op arg
// The following line also displays 100.
System.Console.WriteLine(applyIt2 squareIt num)
// List integerList was defined previously:
//let integerList = [ 1; 2; 3; 4; 5; 6; 7 ]
// You can send the function argument by name, if an appropriate function
// is available. The following expression uses squareIt.
let squareAll = List.map squareIt integerList
// The following line displays [1; 4; 9; 16; 25; 36; 49]
printfn "%A" squareAll
// Or you can define the action to apply to each list element inline.
// For example, no function that tests for even integers has been defined,
// so the following expression defines the appropriate function inline.
// The function returns true if n is even; otherwise it returns false.
let evenOrNot = List.map (fun n -> n % 2 = 0) integerList
// The following line displays [false; true; false; true; false; true; false]
printfn "%A" evenOrNot
// ** RETURN THE VALUE FROM A FUNCTION CALL **
// Function doubleIt is defined in a previous example.
//let doubleIt = fun n -> 2 * n
System.Console.WriteLine(doubleIt 3)
System.Console.WriteLine(squareIt 4)
// The following function call returns a string:
// str is defined in a previous section.
//let str = "F#"
let lowercase = str.ToLower()
System.Console.WriteLine((fun n -> n % 2 = 1) 15)
let checkFor item =
let functionToReturn = fun lst ->
List.exists (fun a -> a = item) lst
functionToReturn
// integerList and stringList were defined earlier.
//let integerList = [ 1; 2; 3; 4; 5; 6; 7 ]
//let stringList = [ "one"; "two"; "three" ]
// The returned function is given the name checkFor7.
let checkFor7 = checkFor 7
// The result displayed when checkFor7 is applied to integerList is True.
System.Console.WriteLine(checkFor7 integerList)
// The following code repeats the process for "seven" in stringList.
let checkForSeven = checkFor "seven"
// The result displayed is False.
System.Console.WriteLine(checkForSeven stringList)
// Function compose takes two arguments. Each argument is a function
// that takes one argument of the same type. The following declaration
// uses lambda expresson syntax.
let compose =
fun op1 op2 ->
fun n ->
op1 (op2 n)
// To clarify what you are returning, use a nested let expression:
let compose2 =
fun op1 op2 ->
// Use a let expression to build the function that will be returned.
let funToReturn = fun n ->
op1 (op2 n)
// Then just return it.
funToReturn
// Or, integrating the more concise syntax:
let compose3 op1 op2 =
let funToReturn = fun n ->
op1 (op2 n)
funToReturn
// Functions squareIt and doubleIt were defined in a previous example.
let doubleAndSquare = compose squareIt doubleIt
// The following expression doubles 3, squares 6, and returns and
// displays 36.
System.Console.WriteLine(doubleAndSquare 3)
let squareAndDouble = compose doubleIt squareIt
// The following expression squares 3, doubles 9, returns 18, and
// then displays 18.
System.Console.WriteLine(squareAndDouble 3)
let makeGame target =
// Build a lambda expression that is the function that plays the game.
let game = fun guess ->
if guess = target then
System.Console.WriteLine("You win!")
else
System.Console.WriteLine("Wrong. Try again.")
// Now just return it.
game
let playGame = makeGame 7
// Send in some guesses.
playGame 2
playGame 9
playGame 7
// Output:
// Wrong. Try again.
// Wrong. Try again.
// You win!
// The following game specifies a character instead of an integer for target.
let alphaGame = makeGame 'q'
alphaGame 'c'
alphaGame 'r'
alphaGame 'j'
alphaGame 'q'
// Output:
// Wrong. Try again.
// Wrong. Try again.
// Wrong. Try again.
// You win!
// ** CURRIED FUNCTIONS **
let compose4 op1 op2 n = op1 (op2 n)
let compose4curried =
fun op1 ->
fun op2 ->
fun n -> op1 (op2 n)
// Access one layer at a time.
System.Console.WriteLine(((compose4 doubleIt) squareIt) 3)
// Access as in the original compose examples, sending arguments for
// op1 and op2, then applying the resulting function to a value.
System.Console.WriteLine((compose4 doubleIt squareIt) 3)
// Access by sending all three arguments at the same time.
System.Console.WriteLine(compose4 doubleIt squareIt 3)
let doubleAndSquare4 = compose4 squareIt doubleIt
// The following expression returns and displays 36.
System.Console.WriteLine(doubleAndSquare4 3)
let squareAndDouble4 = compose4 doubleIt squareIt
// The following expression returns and displays 18.
System.Console.WriteLine(squareAndDouble4 3)
let makeGame2 target guess =
if guess = target then
System.Console.WriteLine("You win!")
else
System.Console.WriteLine("Wrong. Try again.")
let playGame2 = makeGame2 7
playGame2 2
playGame2 9
playGame2 7
let alphaGame2 = makeGame2 'q'
alphaGame2 'c'
alphaGame2 'r'
alphaGame2 'j'
alphaGame2 'q'
// ** IDENTIFIER AND FUNCTION DEFINITION ARE INTERCHANGEABLE **
let isNegative = fun n -> n < 0
// This example uses the names of the function argument and the integer
// argument. Identifier num is defined in a previous example.
//let num = 10
System.Console.WriteLine(applyIt isNegative num)
// This example substitutes the value that num is bound to for num, and the
// value that isNegative is bound to for isNegative.
System.Console.WriteLine(applyIt (fun n -> n < 0) 10)
System.Console.WriteLine((fun op arg -> op arg) (fun n -> n < 0) 10)
// ** FUNCTIONS ARE FIRST-CLASS VALUES IN F# **
//let squareIt = fun n -> n * n
let funTuple2 = ( BMICalculator, fun n -> n * n )
let increments = List.map (fun n -> n + 1) [ 1; 2; 3; 4; 5; 6; 7 ]
//let checkFor item =
// let functionToReturn = fun lst ->
// List.exists (fun a -> a = item) lst
// functionToReturn