F# - 函数

在 F# 中,函数的工作方式类似于数据类型。 您可以像任何其他变量一样声明和使用函数。

由于函数可以像任何其他变量一样使用,因此您可以 −

  • 创建一个具有名称的函数,并将该名称与类型相关联。
  • 为其指定一个值。
  • 对该值执行一些计算。
  • 将其作为参数传递给另一个函数或子例程。
  • 将一个函数作为另一个函数的结果返回。

定义函数

函数是使用let关键字定义的。 函数定义具有以下语法 −

let [inline] function-name parameter-list [ : return-type ]
   = function-body

其中,

  • function-name是代表函数的标识符。

  • parameter-list 给出以空格分隔的参数列表。 您还可以为每个参数指定显式类型,如果未指定,编译器往往会从函数体(如变量)中推断出它。

  • function-body 由一个表达式或由多个表达式组成的复合表达式组成。 函数体中的最后一个表达式就是返回值。

  • return-type 是一个冒号后跟一个类型,并且是可选的。 如果未指定返回类型,则编译器根据函数体中的最终表达式确定它。

函数的参数

在函数名称后面列出参数名称。 您可以指定参数的类型。 参数类型应跟在参数名称后面,并用冒号分隔。

如果未指定参数类型,则由编译器推断。

例如 −

let doubleIt (x : int) = 2 * x

调用函数

通过指定函数名称后跟一个空格,然后指定由空格分隔的任何参数来调用函数。

例如 −

let vol = cylinderVolume 3.0 5.0

以下程序说明了这些概念。

示例 1

以下程序在给定半径和长度作为参数时计算圆柱体的体积

// 该函数计算体积
// 以半径和长度为参数的圆柱体

let cylinderVolume radius length : float =

   // function body
   let pi = 3.14159
   length * pi * radius * radius

let vol = cylinderVolume 3.0 5.0
printfn " Volume: %g " vol

当您编译并执行该程序时,它会产生以下输出 −

Volume: 141.372

示例 2

以下程序返回两个给定参数中较大的值 −

// the function returns the larger value between two
// arguments

let max num1 num2 : int32 =
   // function body
   if(num1>num2)then
      num1
   else
      num2

let res = max 39 52
printfn " Max Value: %d " res

当您编译并执行该程序时,它会产生以下输出 −

Max Value: 52

示例 3

let doubleIt (x : int) = 2 * x
printfn "Double 19: %d" ( doubleIt(19))

当您编译并执行该程序时,它会产生以下输出 −

Double 19: 38

递归函数

递归函数是调用自身的函数。

使用 let rec 关键字组合定义递归。

定义递归函数的语法是 −

//Recursive function definition
let rec function-name parameter-list = recursive-function-body

例如 −

let rec fib n = if n < 2 then 1 else fib (n - 1) + fib (n - 2)

示例 1

以下程序返回 Fibonacci 1 到 10 −

let rec fib n = if n < 2 then 1 else fib (n - 1) + fib (n - 2)
for i = 1 to 10 do
   printfn "Fibonacci %d: %d" i (fib i)

当您编译并执行该程序时,它会产生以下输出 −

Fibonacci 1: 1
Fibonacci 2: 2
Fibonacci 3: 3
Fibonacci 4: 5
Fibonacci 5: 8
Fibonacci 6: 13
Fibonacci 7: 21
Fibonacci 8: 34
Fibonacci 9: 55
Fibonacci 10: 89

示例 2

以下程序返回阶乘 8 −

open System
let rec fact x =
   if x < 1 then 1
   else x * fact (x - 1)
Console.WriteLine(fact 8)

当您编译并执行该程序时,它会产生以下输出 −

40320

F# 中的箭头表示法

F# 使用链式箭头表示法报告函数和值中的数据类型。 让我们举一个接受一个 int 输入并返回一个字符串的函数示例。 用箭头表示法可以写成−

int -> string

数据类型从左到右读取。

让我们假设另一个函数,它接受两个 int 数据输入并返回一个字符串。

let mydivfunction x y = (x / y).ToString();;

F# 使用链式箭头表示法将数据类型报告为 −

val mydivfunction : x:int -> y:int -> string

返回类型由链式箭头表示法中最右边的数据类型表示。

更多示例 −

符号 含义
float → float → float 该函数接受两个float输入,返回另一个float
int → string → float 该函数接受一个int和一个string输入,返回一个float

Lambda 表达式

lambda 表达式 是一个未命名函数。

让我们举两个函数的例子 −

let applyFunction ( f: int -> int -> int) x y = f x y
let mul x y = x * y
let res = applyFunction mul 5 7
printfn "%d" res

当您编译并执行该程序时,它会产生以下输出 −

35

在上面的例子中,如果我们不定义函数mul,,我们可以使用 lambda 表达式作为−

let applyFunction ( f: int -> int -> int) x y = f x y
let res = applyFunction (fun x y -> x * y ) 5 7
printfn "%d" res

当您编译并执行该程序时,它会产生以下输出 −

35

函数组合和管道

在 F# 中,一个函数可以由其他函数组合而成。

下面的示例显示了由两个函数 function1 和 function2 组成的名为 f 的函数 −

let function1 x = x + 1
let function2 x = x * 5

let f = function1 >> function2
let res = f 10
printfn "%d" res

当您编译并执行该程序时,它会产生以下输出 −

55

F# 还提供了一种称为函数管道化的功能。管道化允许将函数调用作为连续操作链接在一起。

下面的例子表明 −

let function1 x = x + 1
let function2 x = x * 5

let res = 10 |> function1 |> function2
printfn "%d" res

当您编译并执行该程序时,它会产生以下输出 −

55