- Published on
OCaml Function Definition
在 OCaml 中,定义函数(function)的方式非常灵活,以下是 5 种常见方法,每种方式都有其适用场景:
基础定义(let + 显式参数)
let add x y = x + y (* 类型: int -> int -> int *)
let result = add 3 5 (* result 的值为 8 *)
特点:
- 柯里化(Currying)风格,自动支持部分应用(如
let add5 = add 5
)。 - 参数和返回值类型通常可自动推断。
匿名函数(fun)
let increment = fun x -> x + 1 (* 类型: int -> int *)
let five = increment 4 (* five 的值为 5 *)
适用场景:
- 作为高阶函数的参数(如
List.map (fun x -> x * 2) [1; 2; 3]
)。 - 需要临时定义简单函数时。
例子
List.map (fun x -> x * 2) [1; 2; 3] (* 结果为 [2; 4; 6] *)
多模式匹配(function 关键字)
let rec factorial = function
| 0 -> 1
| n -> n * factorial (n - 1) (* 类型: int -> int *)
let result = factorial 5 (* result 的值为 120 *)
特点:
- 等价于
fun x -> match x with ...
的简写形式。 - 适合对单一参数进行模式匹配的场景。
带类型标注的定义
let divide (x : float) (y : float) : float option =
if y = 0. then None else Some (x /. y)
let result1 = divide 10.0 2.0 (* result1 的值为 Some 5.0 *)
let result2 = divide 5.0 0.0 (* result2 的值为 None *)
用途:
- 明确指定参数/返回值类型,增强可读性或解决类型歧义。
- 在复杂模块接口中常用。
标签参数和可选参数
let greet ~name ?(greeting = "Hello") () =
Printf.printf "%s, %s!\n" greeting name
greet ~name:"Alice" ();; (* 输出: Hello, Alice! *)
greet ~greeting:"Bonjour" ~name:"Bob";; (* 输出: Bonjour, Bob! *)
特点:
~label
是命名参数,调用时顺序可交换。?(arg = default)
是可选参数,可省略。
进阶技巧
rec
关键字)
递归函数(需 let rec sum_list = function
| [] -> 0
| hd :: tl -> hd + sum_list tl
let result = sum_list [1; 2; 3; 4] (* result 的值为 10 *)
and
连接)
相互递归函数(let rec even n =
if n = 0 then true else odd (n - 1)
and odd n =
if n = 0 then false else even (n - 1)
let result1 = even 4 (* result1 的值为 true *)
let result2 = odd 5 (* result2 的值为 false *)
多态函数(自动泛型)
let first_element lst = match lst with
| [] -> None
| x :: _ -> Some x (* 类型: 'a list -> 'a option *)
let result1 = first_element [1; 2; 3] (* result1 的值为 Some 1 *)
let result2 = first_element ["a"; "b"] (* result2 的值为 Some "a" *)
如何选择?
场景 | 推荐方式 |
---|---|
简单数学运算 | 基础定义 (let add x y ) |
作为参数传递 | 匿名函数 (fun x -> ... ) |
模式匹配主导逻辑 | function 关键字 |
需要明确类型 | 类型标注 ((x : int)) |
API 设计(提高可读性) | 标签参数 (~name) |
注意
- OCaml 的函数默认是 柯里化的,
let f x y = ...
等价于let f = fun x -> fun y -> ...
。 - 所有函数必须有一个返回值(用
()
表示单元类型作为“无返回值”)。
THE END