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