- F# 基础教程
- F# - 首页
- F# - 概述
- F# - 环境设置
- F# - 程序结构
- F# - 基本语法
- F# - 数据类型
- F# - 变量
- F# - 运算符
- F# - 决策
- F# - 循环
- F# - 函数
- F# - 字符串
- F# - 可选项
- F# - 元组
- F# - 记录
- F# - 列表
- F# - 序列
- F# - 集合
- F# - 映射
- F# - 辨析联合
- F# - 可变数据
- F# - 数组
- F# - 可变列表
- F# - 可变字典
- F# - 基本 I/O
- F# - 泛型
- F# - 委托
- F# - 枚举
- F# - 模式匹配
- F# - 异常处理
- F# - 类
- F# - 结构体
- F# - 运算符重载
- F# - 继承
- F# - 接口
- F# - 事件
- F# - 模块
- F# - 命名空间
F# - 函数
在 F# 中,函数就像数据类型一样。你可以像使用其他变量一样声明和使用函数。
由于函数可以像其他变量一样使用,因此您可以:
- 创建一个函数,并为其命名并将其名称与类型关联。
- 为其赋值。
- 对该值执行一些计算。
- 将其作为参数传递给另一个函数或子例程。
- 将函数作为另一个函数的结果返回。
定义函数
函数使用 **let** 关键字定义。函数定义具有以下语法:
let [inline] function-name parameter-list [ : return-type ] = function-body
其中:
**函数名** 是表示函数的标识符。
**参数列表** 给出由空格分隔的参数列表。您还可以为每个参数指定显式类型,如果未指定,编译器会从函数体中推断出来(如变量)。
**函数体** 由表达式或由多个表达式组成的复合表达式组成。函数体中的最后一个表达式是返回值。
**返回类型** 是冒号后跟一个类型,并且是可选的。如果未指定返回类型,则编译器会从函数体中的最后一个表达式确定它。
函数的参数
您在函数名后列出参数名。您可以指定参数的类型。参数的类型应该跟在参数名后面,用冒号分隔。
如果未指定参数类型,则由编译器推断。
例如:
let doubleIt (x : int) = 2 * x
调用函数
通过指定函数名,然后是一个空格,然后是任何用空格分隔的参数来调用函数。
例如:
let vol = cylinderVolume 3.0 5.0
以下程序说明了这些概念。
示例 1
以下程序在给定半径和长度作为参数时计算圆柱体的体积
// the function calculates the volume of // a cylinder with radius and length as parameters 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
以下程序返回斐波那契数列 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